230825 TIL #173 CT_베스트앨범 (해시맵)

김춘복·2023년 8월 25일
0

TIL : Today I Learned

목록 보기
173/543
post-custom-banner

Today I Learned

오늘도 lv.3 랜덤 문제를 풀어보았다. 이번 문제는 해시맵을 사용해서 풀었는데 뭔가 코드가 지저분해졌다. 풀긴 했지만, 이거 말고 좀 더 좋은 방법도 있을 것 같은데 한번 생각해봐야겠다.


베스트앨범

문제

장르별로 가장 많이 재생된 노래를 2곡씩 담아 베스트 앨범을 만들려고 한다. 가장 많이 재생된 장르부터 수록하고, 장르 당 2곡씩 담으려 한다. 2곡이 안되면 1곡만 담는다. 노래는 고유번호로 주어지며, 재생횟수가 같다면 고유번호가 낮은 노래부터 수록한다. 베스트 앨범에 들어갈 노래를 차례대로 int[]에 담아 반환해라.


풀이 과정

  1. 장르 별로 총 스트리밍 횟수, 가장 많이들은 2곡 이렇게 3가지 변수를 plays 배열을 한번 순회하며 다 담아야 하기에 genre를 key로 삼아 해시맵을 만들고 value에 size가 3인 int 배열을 만들어 넣었다.

  2. 맵에 해당 장르가 아직 담긴 적이 없으면 {재생횟수, 곡번호 -1}을 담는다. -1은 아직 1곡밖에 없기때문에 담았다.

  3. 이미 장르에 대한 정보가 담겨있다면, max1, max2값과 비교해서 int배열에 다시 담아 해당 장르를 업데이트 해 다시 넣는다.

  4. 주어진 int배열들을 0번째 인덱스(해당 장르 총 재생 횟수)를 기준으로 정렬한다. map.values()로 value인 int 배열만 가져와서 리스트에 담고 sortedList.sort((a,b) -> Integer.compare(b[0], a[0])); 로 내림차순으로 정렬한다.

  5. 리스트를 stream을 열어 배열로 반환하면 끝.


구현 코드

import java.util.*;
class Solution {
    public int[] solution(String[] genres, int[] plays) {
        int n = plays.length;
        
        // 해시맵 생성
        Map<String, int[]> map = new HashMap<>();
        
        for(int i=0; i<n; i++){
            // 장르를 키로 넣어서 있으면 value 
            int[] a = map.getOrDefault(genres[i], null);
            if(a==null){
                // 장르의 누적 스트리밍수, 최다 스트리밍 노래 번호, 2번째 스트리밍 노래 번호
                int[] b = new int[]{plays[i], i, -1};
                map.put(genres[i], b);
            } else {
                // 현재 순회중인 노래의 스트리밍 수
                int now = plays[i];
                // 이 장르의 현재까지 최다 스트리밍 수
                int max1 = plays[a[1]];
                // 이 장르의 현재까지 2번째 많은 스트리밍 수
                int max2 = -1;
                if(a[2]!=-1){
                    max2 = plays[a[2]];
                }
                
                int[] c = new int[3];
                c[0] = a[0] + now;
                // 현재 순회중인 노래가 최다 스트리밍일 때
                if(now > max1){
                    c[1] = i;
                    c[2] = a[1];
                // 두 번째 최다 스트리밍일 때
                } else if (now > max2){
                    c[1] = a[1];
                    c[2] = i;
                } else {
                    // 그 이하일 때
                    c[1] = a[1];
                    c[2] = a[2];
                }
                // key로 장르제목, value로 int[]를 삽입한다.
                map.put(genres[i], c);
            }
            
        }
        
        // 해시맵을 누적 스트리밍(int[]의 0번째 인덱스)을 기준으로 내림차순 정렬한다.
        List<int[]> sortedList = new ArrayList<>(map.values());
        sortedList.sort((a,b) -> Integer.compare(b[0], a[0]));
        
        List<Integer> result = new ArrayList<>();
        
        // 정렬된 리스트를 순회하면서 1번값과 2번값(있으면)을 넣는다.
        for(int[] arr : sortedList){
            result.add(arr[1]);
            if(arr[2] != -1) result.add(arr[2]);
        }
        int[] answer = result.stream().mapToInt(Integer::intValue).toArray();
        
        return answer;
    }
}

알게된 것

  • 해시맵의 특수한 메서드
  1. boolean containsKey(Object key) : 해당 key 값이 있는지 확인

  2. boolean containsValue(Object value) : 해당 value 값이 있는지 확인

  3. V getOrDefault(Object key, V defaultValue) : 해당 key값이 있으면 value를 반환하고 없으면 뒤의 디폴트값을 반환

  4. V putIfAbsent(K key, V value) : 해당 key 값이 없으면 <key,value>를 입력한다. 있으면 value를 반환한다.

  5. Collection<V> values() : value값들을 컬렉션에 담아 반환한다.
    List<int[]> sortedList = new ArrayList<>(map.values()); 처럼 쓴다.

  6. Set<Map.Entry<K,V>> entrySet() : <K,V>의 entrySet을 set에 담아 반환한다.

profile
Backend Dev / Data Engineer
post-custom-banner

0개의 댓글