본문 바로가기
알고리즘/프로그래머스

[프로그래머스] 베스트앨범 (level3) java

by 코리늬 2019. 12. 17.

주말 + 평일 틈틈이 풀었음에도 꼬박 일주일이나 걸렸다..

질문으로 도움까지 요청하며 정말 겨우 해결했다.

문제는 링크로 대체.

    // 요구사항 정리
    // 1. 가장 많이 재생된 장르를 찾는다
    // 2. 같은 장르의 노래중 재생 횟수가 높은 노래가 먼저 재생된다.
    // 3. 재생횟수가 같은 경우에는 인덱스가 낮은 노래가 먼저 재생된다.
    public int[] solution(String[] genres, int[] plays) {
        int[] answer = {};
        Map<String,Integer> topPlay = new HashMap<>();
        Map<String,Map<Integer,Integer>> firstSong = new HashMap<>();
        Map<Integer,Integer> countList = null;

        int genLength = genres.length;

        for(int i=0; i<genLength; i++){
            //1번 요구사항을 구하기 위해, 같은 장르이면 +
            if(topPlay.get(genres[i]) == null){
                topPlay.put(genres[i], plays[i]);
            }else{
                topPlay.put(genres[i], topPlay.get(genres[i])+plays[i]);
            }
            //3항 연산자로 나타낸다면
            //topPlay.put(genres[i], topPlay.containsKey(genres[i]) ? topPlay.get(genres[i])+plays[i] : plays[i]) ;

            if(firstSong.containsKey(genres[i])){
                countList = firstSong.get(genres[i]);
            }else{
                countList = new HashMap<>();
            }
            //3항 연산자로 나타낸다면
            //Map<Integer,Integer> countList = firstSong.containsKey(genres[i]) ? firstSong.get(genres[i]) : new HashMap<>();

            countList.put(i,plays[i]);
            firstSong.put(genres[i],countList);
        }


        //리스트에 map의 키 값 담기
        List<String> topPlayKey = new ArrayList<>(topPlay.keySet());

        Collections.sort(topPlayKey, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                //내림차순, value 값으로 정렬
                return topPlay.get(o2).compareTo(topPlay.get(o1));
                //오름차순
                // return topPlay.get(o1).compareTo(topPlay.get(o2));
            }
        });

        //System.out.println("firstSong : " + firstSong);
        //키값을 정렬했으니 키 값 순서대로 그 안의 map을 정렬하면된다.
        List<Integer> temp = new ArrayList<>();
        for (String key : topPlayKey) {
            List<Map.Entry<Integer, Integer>> list = new ArrayList<>(firstSong.get(key).entrySet());

            Collections.sort(list, new Comparator<Map.Entry<Integer, Integer>>() {
                @Override
                public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
                    if (o1.getValue() == o2.getValue()){
                        return o1.getKey().compareTo(o2.getKey());
                    }else{
                        return o2.getValue().compareTo(o1.getValue());
                    }
                }
            });

            Map<Integer,Integer> map = new HashMap<>();
            map.entrySet().toArray();

            int index = 0;
            for (Map.Entry<Integer, Integer> entrys : list)
            {
                if(index < 2){
                    int entrysKey = entrys.getKey();
                    temp.add(entrysKey);
                    index++;
                }
            }
        }

        answer = new int[temp.size()];
        for(int i=0; i<temp.size(); i++){
            answer[i] = temp.get(i);
        }

        return answer;
    }

우선, 가장 많이 재생된 장르를 찾는것이 첫 번째 목표다.

장르별 재생횟수를 전부 더해준다. 이제 진짜 시작이다 ㅎ

위 조건대로 비교를 하기 위해서는 장르별로 나눠서 담아야 한다.

class={~~}, pop={~~}

그렇게 하기 위해서 장르를 키 값으로 가지고, 나중에 그 안의 인덱스 들을 또 정렬하기위해

Map<String,Map<Integer,Integer>>를 선언했다.

그리고 장르 별 재생 횟수를 저장 할 Map<Integer,Integer>를 하나 더 선언했다.

 

장르의 종류 갯수 만큼 반복하면서

if

firstSong의 키값이 해당 장르를 포함하고 있으면 value 값을 key, value(인덱스, 재생횟수)로 저장한다.

else

여기로 왔다면 처음 들어오는 장르인것이다.

그대로 추가해주도록한다.

 

여기까지 값을 비교하기 위해 map에 담는 작업이 끝났다.

이것도 너무 애를 먹었다

  • 이제 먼저 재생 될 노래를 찾기 위해 정렬을 해줘야한다.

  • 정렬은 Comparator를 사용했다.

처음에 구글링을 하다가 TreeMap의 생성자로 일반맵?을 넣으면 정렬이 된다는 글을 보고 신나게 사용했지만,

사전적인 abc정렬만 가능해서 결국 못쓰게되었다.

 

이제 가장 많이 재생된 장르가 제일 처음으로 나온다.

그렇다면 그에 따른 인덱스들을 비교 정렬해야한다.

여기가 제일 어려웠다.

정렬한 장르를 key값으로 사용해서 정렬을 할건데, Map을 정렬하려면 List를 사용해야 했다.

소스에는 Map.Entry만 보이지만, 최초에는 단순히 List Map 구조였다.

정렬에서 결국 value값을 비교하는데 실패하고 Entry를 사용해야 함을 알게 되었지만 너무나도 많은 시간이 걸렸다.

List<Map.Entry<Integer, Integer>> list = new ArrayList<>(firstSong.get(key).entrySet());

value값이 같으면 낮은 인덱스를 사용하기로 했으므로 오름차순, 그 외의 경우는 다 내림차순으로 정렬했다.

 

이렇게 정렬이 다 끝났다. 후..

이제 배열에 담기만 하면되는데 List Map.Entry를 배열에 어떻게 담아..?

코테 문제를 한 4개정도 푸는 느낌이다.

 

장르는 최대 2종류 이므로 index를 2까지만 주고, 마찬가지로 인덱스 값을 저장할 List를 하나 더 선언했다.

그리고 정렬된 key 값을 2번씩만 담아서 리스트를 배열로 다시 담아주는 작업을 거쳤다.

레벨3을 제대로 끝까지 풀어본건 거의 처음인데 정말 너무 어렵고 또 한 번 벽을 느꼈다..

댓글