728x90
반응형

베스트앨범 - 3Level

문제설명

스트리밍 사이트에서 장르 별로 가장 많이 재생된 노래를 두 개씩 모아 베스트 앨범을 출시하려 합니다. 노래는 고유 번호로 구분하며, 노래를 수록하는 기준은 다음과 같습니다.

  1. 속한 노래가 많이 재생된 장르를 먼저 수록합니다.
  2. 장르 내에서 많이 재생된 노래를 먼저 수록합니다.
  3. 장르 내에서 재생 횟수가 같은 노래 중에서는 고유 번호가 낮은 노래를 먼저 수록합니다.

노래의 장르를 나타내는 문자열 배열 genres와 노래별 재생 횟수를 나타내는 정수 배열 plays가 주어질 때, 베스트 앨범에 들어갈 노래의 고유 번호를 순서대로 return 하도록 solution 함수를 완성하세요.

 

제한사항

  • genres[i]는 고유번호가 i인 노래의 장르입니다.
  • plays[i]는 고유번호가 i인 노래가 재생된 횟수입니다.
  • genres와 plays의 길이는 같으며, 이는 1 이상 10,000 이하입니다.
  • 장르 종류는 100개 미만입니다.
  • 장르에 속한 곡이 하나라면, 하나의 곡만 선택합니다.
  • 모든 장르는 재생된 횟수가 다릅니다.

입출력 예

입출력 예 설명

classic 장르는 1,450회 재생되었으며, classic 노래는 다음과 같습니다.

  • 고유 번호 3: 800회 재생
  • 고유 번호 0: 500회 재생
  • 고유 번호 2: 150회 재생

pop 장르는 3,100회 재생되었으며, pop 노래는 다음과 같습니다.

  • 고유 번호 4: 2,500회 재생
  • 고유 번호 1: 600회 재생

따라서 pop 장르의 [4, 1]번 노래를 먼저, classic 장르의 [3, 0]번 노래를 그다음에 수록합니다.

 

풀이

해당 문제는 HashMap 정렬을 이용하여 풀었는데, 생각보다 처리 시간이 많이 나옵니다. 다른 방법이 있는지 조금 더 생각할 필요가 있을것 같습니다.

저는 일단 각 장르의 재생횟수가 많은 것을 기준으로 정렬을 하였고, 해당 장르의 고유번호, 재생횟수를 가지는 Music이라는 객체를 만들어 제가 정의한 정렬기준으로 정렬하여 PriorityQueue 를 이용하여 풀었습니다. 아무래도 이중 루프를 돌다보니 시간이 걸리는 것 같습니다.

import java.util.*;
import java.util.Map.*;

class Solution {
    
    public static class Music implements Comparable<Music>{
        int music_num;
        int plays_cnt;
        
        Music(int a, int b){
            this.music_num = a;
            this.plays_cnt = b;
        }
        
        @Override
        public int compareTo(Music tar){
            // 많이 재생된 것
            if(tar.plays_cnt > this.plays_cnt) return 1;
            if(tar.plays_cnt < this.plays_cnt) return -1;
            // 재생수가 같다면 고유번호가 낮은것
            if(tar.music_num < this.music_num) return 1;
            if(tar.music_num > this.music_num) return -1;
            return 0;
        }
        
    }
    
    public Integer[] solution(String[] genres, int[] plays) {
        
        int len = genres.length;
        HashMap<String,Integer> map = new HashMap<String,Integer>();
        for(int i=0; i<len; i++){
       
            if(map.containsKey(genres[i])){
                map.put(genres[i], map.get(genres[i]) + plays[i]);
            }else{
                map.put(genres[i], plays[i]);
            }
            
        }
        
        // map을 value 기준으로 정렬한다.
		List<Entry<String, Integer>> list_entries = new ArrayList<Entry<String, Integer>>(map.entrySet());

		// 비교함수 Comparator를 사용하여 내림차순으로 정렬
		Collections.sort(list_entries, new Comparator<Entry<String, Integer>>() {
			// compare로 값을 비교
			public int compare(Entry<String, Integer> obj1, Entry<String, Integer> obj2) {
				// 내림 차순 정렬
				return obj2.getValue().compareTo(obj1.getValue());
			}
		});
        
        
        ArrayList<Integer> alist = new ArrayList<Integer>();
        
        // 내림차순으로 정렬된 내용으로 출력한다.
        for(Entry<String, Integer> entry : list_entries) {
            String key = entry.getKey();
            //System.out.println(key + ":" + map.get(key));
            
            PriorityQueue<Music> pq = new PriorityQueue<Music>();
            for(int i=0; i<len; i++){
                if(key.equals(genres[i])) {
                    pq.add(new Music(i, plays[i]));
                }  
            }
            
            int loop=0;
            while(!pq.isEmpty()){
                if(loop==2) break; // 2개만 필요하기때문에 최대 두번만 돌린다.
                Music now = pq.poll();
                alist.add(now.music_num);
                loop++;
            }
        }
        
        //저장된 ArrayList 변수를 Integer[] 배열로 변환한다.
        Integer[] answer = alist.toArray(new Integer[alist.size()]);
        
        
        return answer;
    }
}

결과

728x90
반응형
728x90
반응형

위장 - 2Level

문제설명

스파이들은 매일 다른 옷을 조합하여 입어 자신을 위장합니다.

예를 들어 스파이가 가진 옷이 아래와 같고 오늘 스파이가 동그란 안경, 긴 코트, 파란색 티셔츠를 입었다면 다음날은 청바지를 추가로 입거나 동그란 안경 대신 검정 선글라스를 착용하거나 해야 합니다.

스파이가 가진 의상들이 담긴 2차원 배열 clothes가 주어질 때 서로 다른 옷의 조합의 수를 return 하도록 solution 함수를 작성해주세요.

 

제한사항

  • clothes의 각 행은 [의상의 이름, 의상의 종류]로 이루어져 있습니다.
  • 스파이가 가진 의상의 수는 1개 이상 30개 이하입니다.
  • 같은 이름을 가진 의상은 존재하지 않습니다.
  • clothes의 모든 원소는 문자열로 이루어져 있습니다.
  • 모든 문자열의 길이는 1 이상 20 이하인 자연수이고 알파벳 소문자 또는 '_' 로만 이루어져 있습니다.
  • 스파이는 하루에 최소 한 개의 의상은 입습니다.

입출력 예

입출력 예 설명

예제 #1
headgear에 해당하는 의상이 yellow_hat, green_turban이고 eyewear에 해당하는 의상이 blue_sunglasses이므로 아래와 같이 5개의 조합이 가능합니다.

1. yellow_hat 2. blue_sunglasses 3. green_turban 4. yellow_hat + blue_sunglasses 5. green_turban + blue_sunglasses

예제 #2
face에 해당하는 의상이 crow_mask, blue_sunglasses, smoky_makeup이므로 아래와 같이 3개의 조합이 가능합니다.

1. crow_mask 2. blue_sunglasses 3. smoky_makeup

 

풀이

이번 문제 해시를 이용해 푸는 문제로, clothes 배열에서 종류인 인덱스 1의 값이 중요합니다. 종류에 몇가지가 들어있는지를 HashMap 변수 map에 넣고 해당 종류가 있는지 없는지 체크합니다. 여기서 없을때 새로 map에 넣어줘야 하는데 이때 1이 아닌 2를 넣어줘야 합니다. 왜냐하면 옷을 입지 않을 경우도 생각을 해야하기 때문입니다. 그래야 경우의 수를 계산하기 편합니다.

import java.util.*;

class Solution {
    public int solution(String[][] clothes) {
        int answer = 1;
        
        HashMap<String, Integer> map = new HashMap<String, Integer>();
        
        for(int i=0; i<clothes.length; i++){
            if(map.containsKey(clothes[i][1])){
                map.put(clothes[i][1], map.get(clothes[i][1])+1);  
            }else{
                // 옷은 1개이지만 입지않는 경우도 있기때문에 입은경우 , 안입은 경우의 두가지 경우가 있어 2로 입력
                map.put(clothes[i][1], 2);   
            }                
        }
              
        for(String key : map.keySet()){
            answer *= map.get(key);
        }
        
        
        return answer-1;
    }
   
}

 

결과

728x90
반응형
728x90
반응형

완주하지 못한 선수(1Level)

문제설명

수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.

마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.

 

제한사항

  • 마라톤 경기에 참여한 선수의 수는 1명 이상 100,000명 이하입니다.
  • completion의 길이는 participant의 길이보다 1 작습니다.
  • 참가자의 이름은 1개 이상 20개 이하의 알파벳 소문자로 이루어져 있습니다.
  • 참가자 중에는 동명이인이 있을 수 있습니다.

입출력 예

입출력 예 설명

예제 #1
"leo"는 참여자 명단에는 있지만, 완주자 명단에는 없기 때문에 완주하지 못했습니다.

예제 #2
"vinko"는 참여자 명단에는 있지만, 완주자 명단에는 없기 때문에 완주하지 못했습니다.

예제 #3
"mislav"는 참여자 명단에는 두 명이 있지만, 완주자 명단에는 한 명밖에 없기 때문에 한명은 완주하지 못했습니다.

 

풀이

이 문제는 해시를 얼마나 알고있는지에 대한 문제입니다. 해시를 쓰면 간단하게 Key를 통해 Value를 알 수 있습니다.

이 문제에는 함정이 있는데, 그건 바로 "참가자 중에는 동명이인이 있을 수 있습니다." 라는 것입니다. key값은 중복을 허용하지 않기때문에 이부분에 대한 내용을 어떻게 풀까가 중요한 것 같습니다.

import java.util.*;

class Solution {
    public String solution(String[] participant, String[] completion) {
        String answer = "";
        
        HashMap<String, Integer> map = new HashMap<String, Integer>();
        for(int i=0; i<participant.length ; i++){    
            if(map.get(participant[i]) == null){
                map.put(participant[i], 1);
            }else{
                map.put(participant[i], map.get(participant[i])+1);
            }
        }

        for(int i=0; i<completion.length ; i++){   
            if(map.get(completion[i]) != null){
                map.put(completion[i], map.get(completion[i])-1);
            }
        }
        
        for(int i=0; i<participant.length ; i++){  
            if(map.get(participant[i]) != 0){
                answer = participant[i] ;
                break;
            }
        }
        
        
        return answer;
    }
}

결과

728x90
반응형
728x90
반응형

단어변환

문제설명

두 개의 단어 begin, target과 단어의 집합 words가 있습니다. 아래와 같은 규칙을 이용하여 begin에서 target으로 변환하는 가장 짧은 변환 과정을 찾으려고 합니다.

  1. 한 번에 한 개의 알파벳만 바꿀 수 있습니다.
  2. words에 있는 단어로만 변환할 수 있습니다.

예를 들어 begin이 "hit", target가 "cog", words가 ["hot","dot","dog","lot","log","cog"]라면 "hit" -> "hot" -> "dot" -> "dog" -> "cog"와 같이 4단계를 거쳐 변환할 수 있습니다.

두 개의 단어 begin, target과 단어의 집합 words가 매개변수로 주어질 때, 최소 몇 단계의 과정을 거쳐 begin을 target으로 변환할 수 있는지 return 하도록 solution 함수를 작성해주세요.

 

제한사항

  • 각 단어는 알파벳 소문자로만 이루어져 있습니다.
  • 각 단어의 길이는 3 이상 10 이하이며 모든 단어의 길이는 같습니다.
  • words에는 3개 이상 50개 이하의 단어가 있으며 중복되는 단어는 없습니다.
  • begin과 target은 같지 않습니다.
  • 변환할 수 없는 경우에는 0를 return 합니다.

입출력 예

  • 각 단어는 알파벳 소문자로만 이루어져 있습니다.
  • 각 단어의 길이는 3 이상 10 이하이며 모든 단어의 길이는 같습니다.
  • words에는 3개 이상 50개 이하의 단어가 있으며 중복되는 단어는 없습니다.
  • begin과 target은 같지 않습니다.
  • 변환할 수 없는 경우에는 0를 return 합니다.

입출력 예 설명

예제 #1
문제에 나온 예와 같습니다.

예제 #2
target인 "cog"는 words 안에 없기 때문에 변환할 수 없습니다.

 

풀이

해당문제는 전형적인 BFS문제입니다. BFS 문제의 경우 "최단","최소"를 찾는 경우가 많습니다. 문제에서도 단어가 변환되는 최소의 단계를 구하는 것이기 때문에 BFS 알고리즘을 사용하여 풀면 되겠습니다.

BFS 알고리즘의 설명은 아래를 참고하여 주십시오.

https://tylee82.tistory.com/329?category=940295 
 

[JAVA] 너비 우선 탐색 BFS(Breadth-first search)

동작방식 하나로 시작 정점을 방문한 후 시작 정점에 인접한 모든 정점들을 우선 방문하는 방법입니다. 더 이상 방문하지 않은 정점이 없을 때까지 방문하지 않은 모든 정점들에 대해서도 너비

tylee82.tistory.com

 

이외에도 isCanChange 함수에서 문자1(str1)과 문자2(str2)를 비교해 한개의 알파벳만 변환을 했는지 검사를 하는 함수가 있습니다. 저는 str1과 str2의 문자 하나하나를 char로 변환하여 빼기를 하여 절대값을 해주었습니다. 이렇게하면 문자의 차이가 나오는데 같은 문자라면 '0'이 나타날 것 입니다. '0'이 아닌 위치는 알파벳이 변환이 되었으니 이후에 나오는 알파벳은 모두 '0'이 나와야 한다는 가정으로 새우고 함수를 만들었습니다.

import java.util.*;

class Solution {
    
    class Word{
        String str;
        int count;
        
        Word(String str, int count){
            this.str = str;
            this.count = count;
        }
    }
    
    
    public boolean isCanChange(String str1, String str2){
    	//한 번에 한 개의 알파벳만 바꿀 수 있습니다.
        boolean ret = false;
        
        int len = str1.length();
        
        boolean isOneChange = false;
        int diffWord = 0;
        for(int i=0; i<len; i++){
            diffWord = Math.abs(str1.charAt(i) - str2.charAt(i));
            
            if(!isOneChange && diffWord != 0) {
            	isOneChange = true;
            	ret = true;
            }else if(isOneChange && diffWord != 0){
            	ret = false;
            	break;
            }
        }
        
        return ret;
    }

    
    public int solution(String begin, String target, String[] words) {
        int answer = 0;
        
        int[] used = new int[words.length]; // 사용한것은 1, 안한것은 0
        Queue<Word> q = new LinkedList<Word>();
        q.add(new Word(begin, 0)); //시작점
        
        while(!q.isEmpty()){
            
            Word cur = q.poll();
            
            if(cur.str.equals(target)){
                // terget과 문자가 동일하면 cur.count 반환하고 멈춤
                answer = cur.count;
                break;
            }
            
            for(int i=0; i<words.length; i++){
                if(isCanChange(cur.str, words[i] ) && used[i] == 0) //변환이 가능하고 사용하지 않았으면 q에 넣어준다.
                {
                    used[i] = 1; // 방문 표시
                    q.add(new Word(words[i] , cur.count+1));
                }
            }
            
        }
        
        
        return answer;
    }
}

결과

 

728x90
반응형

+ Recent posts