오늘도 lv.3 랜덤 문제를 풀어보았다. 이번 문제는 해시맵을 사용해서 풀었는데 뭔가 코드가 지저분해졌다. 풀긴 했지만, 이거 말고 좀 더 좋은 방법도 있을 것 같은데 한번 생각해봐야겠다.
장르별로 가장 많이 재생된 노래를 2곡씩 담아 베스트 앨범을 만들려고 한다. 가장 많이 재생된 장르부터 수록하고, 장르 당 2곡씩 담으려 한다. 2곡이 안되면 1곡만 담는다. 노래는 고유번호로 주어지며, 재생횟수가 같다면 고유번호가 낮은 노래부터 수록한다. 베스트 앨범에 들어갈 노래를 차례대로 int[]에 담아 반환해라.
장르 별로 총 스트리밍 횟수, 가장 많이들은 2곡 이렇게 3가지 변수를 plays 배열을 한번 순회하며 다 담아야 하기에 genre를 key로 삼아 해시맵을 만들고 value에 size가 3인 int 배열을 만들어 넣었다.
맵에 해당 장르가 아직 담긴 적이 없으면 {재생횟수, 곡번호 -1}을 담는다. -1은 아직 1곡밖에 없기때문에 담았다.
이미 장르에 대한 정보가 담겨있다면, max1, max2값과 비교해서 int배열에 다시 담아 해당 장르를 업데이트 해 다시 넣는다.
주어진 int배열들을 0번째 인덱스(해당 장르 총 재생 횟수)를 기준으로 정렬한다. map.values()로 value인 int 배열만 가져와서 리스트에 담고 sortedList.sort((a,b) -> Integer.compare(b[0], a[0]));
로 내림차순으로 정렬한다.
리스트를 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;
}
}
boolean containsKey(Object key) : 해당 key 값이 있는지 확인
boolean containsValue(Object value) : 해당 value 값이 있는지 확인
V getOrDefault(Object key, V defaultValue) : 해당 key값이 있으면 value를 반환하고 없으면 뒤의 디폴트값을 반환
V putIfAbsent(K key, V value) : 해당 key 값이 없으면 <key,value>를 입력한다. 있으면 value를 반환한다.
Collection<V> values() : value값들을 컬렉션에 담아 반환한다.
List<int[]> sortedList = new ArrayList<>(map.values());
처럼 쓴다.
Set<Map.Entry<K,V>> entrySet() : <K,V>의 entrySet을 set에 담아 반환한다.