문제의 조건에 따르면 노래를 재생 할 때, (가장 많이 재생한 장르) > (장르 내 많이 재생한 장르(if 재생 횟수가 동일할 경우 고유번호가 낮은 순으로 정렬)) 에 따라 곡을 수록해야한다.
HashMap<String, Integer> genresPlayCnt = new HashMap<String, Integer>();
!!음악 재생 횟수가 많을수록 우선순위가 높으며, 재생 횟수가 동일할 경우 고유번호가 낮은 순으로 정렬하도록 Comparable 인터페이스를 구현한다
public class Music implements Comparable<Music>{
int uniqNum; //고유번호
int plays; //재생횟수
public Music (int uniqNum, int plays) {
this.uniqNum = uniqNum;
this.plays = plays;
}
@Override
public int compareTo(Music music) { //음악 재생횟수가 많은것을 앞에 위치
if(this.plays < music.plays) { return 1;}
else if(this.plays > music.plays) { return -1;}
else {
if(this.uniqNum > music.uniqNum) { return 1; }
else if(this.uniqNum == music.uniqNum) { return 0; }
else { return -1; }
}
}
}
HashMap<String, ArrayList<Music>> musicList = new HashMap<String, ArrayList<Music>>();
위와같이 자료구조를 HashMap으로 설계하고 값을 정렬해야할 경우, 이는 Comparator 인터페이스를 구현하여 수행할 수 있다.
Comparable은 이전에 게시물을 통해 사용예시를 바탕으로 설명한 적 있다.
Comparable의 설명과 사용방법 링크
: Comparable은 compareTo()메소드를 오버라이딩해, 정렬의 기준을 만들어 오름차순 또는 내림차순으로 정렬할 수 있다.
: Comparator는 객체간 특정한 기준에 따라 정렬하고 싶을 때 사용하거나, Comparable의 구현 없이 객체를 정렬하고 싶을 때 사용한다. 정렬의 기준은 compare(Object ob1, Object ob2)메소드의 구현을 통해 정할 수 있다.
리턴타입 | 메소드 |
---|---|
int | compare(T o1, T o2) |
HashMap을 정렬하기 전에 먼저 데이터를 각 변수에 저장하자
HashMap<String, Integer> genresPlayCnt = new HashMap<String, Integer>(); //장르별로 플레이된 카운트 저장
HashMap<String, ArrayList<Music>> musicList = new HashMap<String, ArrayList<Music>>(); //장르별 노래 저장
for(int i=0; i<genres.length; i++) {
if(genresPlayCnt.containsKey(genres[i])) {
genresPlayCnt.put(genres[i], (genresPlayCnt.get(genres[i]) + plays[i])); //재생횟수 더해주기
} else { //새로운 값 넣어주기
genresPlayCnt.put(genres[i], new Integer(plays[i]));
//hashMap생성
musicList.put(genres[i], new ArrayList<Music>());
}
//장르에 따른 Music객체 생성해서 넣기
ArrayList<Music> tempMusicList = musicList.get(genres[i]);
tempMusicList.add(new Music(i, plays[i]));
musicList.put(genres[i], tempMusicList);
}
예시)
- Input :
genres plays [classic, pop, classic, classic, pop] [500, 600, 150, 800, 2500]
- 위의 코드 실행 이후 자료구조
(1) genresPlayCnt
Key Value "classic" 1450 "pop" 3100 (2) musicList
Key Value "classic" (0, 500), (2, 150), (3, 800) "pop" (1, 600), (4, 2500)
//genresPlayCnt를 value로 정렬하기(내림차순)
//Map.Entry리스트를 생성한다
List<Map.Entry<String, Integer>> entries = new ArrayList<Map.Entry<String, Integer>>(genresPlayCnt.entrySet());
//Comparator를 사용해 내림차순으로 정렬한다
Collections.sort(entries, new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> obj1, Map.Entry<String, Integer> obj2) {
if(obj1.getValue() < obj2.getValue()) return 1;
else if(obj1.getValue() == obj2.getValue()) return 0;
else return -1;
}
});
위의 public int compare() 메소드는 아래와 같이 더 간단하게 작성할 수 있다.
public int compare(Map.Entry<String, Integer> obj1, Map.Entry<String, Integer> obj2) {
return obj2.getValue().compareTo(obj1.getValue());
}
ArrayList<Integer> tempAnswer = new ArrayList<Integer>(); //수록할 곡의 고유번호를 저장한다
String musicGenre = "";
for(Map.Entry<String, Integer> entry : entries) {
musicGenre = entry.getKey(); //장르 알아내서
ArrayList<Music> sortMusicList = musicList.get(musicGenre); //장르에 해당하는 Music List가져오고
Collections.sort(sortMusicList); //정렬한다
//최대 두 곡을 수록한다
if(sortMusicList.size() < 2) {
for(int i=0; i<sortMusicList.size(); i++) {
tempAnswer.add(sortMusicList.get(i).uniqNum);
}
} else {
for(int i=0; i<2; i++) {
tempAnswer.add(sortMusicList.get(i).uniqNum);
}
}
}
import java.util.*;
class Solution {
public class Music implements Comparable<Music>{
int uniqNum; //고유번호
int plays; //재생횟수
public Music (int uniqNum, int plays) {
this.uniqNum = uniqNum;
this.plays = plays;
}
@Override
public int compareTo(Music music) { //음악 재생횟수가 많은것을 앞에 위치
if(this.plays < music.plays) { return 1;}
else if(this.plays > music.plays) { return -1;}
else {
if(this.uniqNum > music.uniqNum) { return 1; }
else if(this.uniqNum == music.uniqNum) { return 0; }
else { return -1; }
}
}
}
public int[] solution(String[] genres, int[] plays) {
int[] answer = {};
HashMap<String, Integer> genresPlayCnt = new HashMap<String, Integer>(); //장르별로 플레이된 카운트 저장
HashMap<String, ArrayList<Music>> musicList = new HashMap<String, ArrayList<Music>>(); //장르별 노래 저장
for(int i=0; i<genres.length; i++) {
if(genresPlayCnt.containsKey(genres[i])) {
genresPlayCnt.put(genres[i], (genresPlayCnt.get(genres[i]) + plays[i])); //재생횟수 더해주기
} else { //새로운 값 넣어주기
genresPlayCnt.put(genres[i], new Integer(plays[i]));
//hashMap생성
musicList.put(genres[i], new ArrayList<Music>());
}
//장르에 따른 Music객체 생성해서 넣기
ArrayList<Music> tempMusicList = musicList.get(genres[i]);
tempMusicList.add(new Music(i, plays[i]));
musicList.put(genres[i], tempMusicList);
}
//genresPlayCnt를 value로 정렬하기(내림차순)
List<Map.Entry<String, Integer>> entries = new ArrayList<Map.Entry<String, Integer>>(genresPlayCnt.entrySet());
Collections.sort(entries, new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> obj1, Map.Entry<String, Integer> obj2) {
if(obj1.getValue() < obj2.getValue()) return 1;
else if(obj1.getValue() == obj2.getValue()) return 0;
else return -1;
}
});
ArrayList<Integer> tempAnswer = new ArrayList<Integer>(); //answer값 임시 저장
String musicGenre = "";
for(Map.Entry<String, Integer> entry : entries) {
musicGenre = entry.getKey(); //장르 알아내서
ArrayList<Music> sortMusicList = musicList.get(musicGenre); //장르에 해당하는 Music List가져오고
Collections.sort(sortMusicList); //정렬한다
//최대 두 곡을 수록한다
if(sortMusicList.size() < 2) {
for(int i=0; i<sortMusicList.size(); i++) {
tempAnswer.add(sortMusicList.get(i).uniqNum);
}
} else {
for(int i=0; i<2; i++) {
tempAnswer.add(sortMusicList.get(i).uniqNum);
}
}
}
answer = new int[tempAnswer.size()];
for(int i=0; i<tempAnswer.size(); i++) {
answer[i] = tempAnswer.get(i);
}
return answer;
}
}
참고
TreeSet과 TreeMap 자료구조는 키의 저장과 동시에 자동으로 오름차순으로 정렬되는데, 이때 정렬을 위해 java.lang.comparable을 구현한 객체를 요구한다. (Integer, Double, String,.. 은 모두 Comparable 인터페이스를 구현하고 있으므로 기본 정렬시 별도로 구현하지 않아도 된다)
즉, 사용자 정의 클래스도 Comparable을 구현하면 TreeSet과 TreeMap을 사용한 자동 정렬이 가능하다.