코테/lvl3

프로그래머스 베스트앨범(lvl3) 풀어보기

디비드킴 2026. 10. 2. 15:50

문제링크

https://school.programmers.co.kr/learn/courses/30/lessons/42579

 

프로그래머스

SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr


문제 핵심

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

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

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


알고리즘

1.장르별 재생횟수 & 장르별 곡분리 구함

2.장르별 재생횟수 내림차순정렬 & 장르별 곡재생횟수로 내림차순정렬->동률이면 index 낮은순으로 정렬

3.각장르에서 두곡씩 선택 


코드

public static  List<Integer>  solution(String[] genres, int[] plays) {
        List<Integer> answer = new LinkedList<>();
        Map<String, Integer> cateAndCount = new HashMap<>();
        Map<String, List<int[]>> cateAndSongs = new HashMap<>();
        for (int i = 0; i < genres.length; i++) {
            if (cateAndCount.containsKey(genres[i])) {
                int oc = cateAndCount.get(genres[i]);
                cateAndCount.put(genres[i], oc + plays[i]);
            } else {
                cateAndCount.put(genres[i], plays[i]);
            }
            if (!cateAndSongs.containsKey(genres[i])) {
                List<int[]> songs = new ArrayList<>();
                songs.add(new int[]{i, plays[i]});
                cateAndSongs.put(genres[i], songs);
            } else {
                cateAndSongs.get(genres[i]).add(new int[] { i, plays[i] });
            }

        }
        List<Map.Entry<String, Integer>> sortedList = new ArrayList<>(cateAndCount.entrySet());
        sortedList.sort((a, b) -> b.getValue().compareTo(a.getValue()));
        System.out.println(sortedList);
        cateAndSongs.forEach((k, v) -> v.sort((a, b) -> {
            if (a[1] == b[1]) {
                return Integer.compare(a[0], b[0]);
            }
            return Integer.compare(b[1], a[1]);
        }));
        cateAndSongs.forEach((k, v) -> System.out.println(k + " = " + v.stream().map(Arrays::toString).toList()));
        for (Map.Entry<String, Integer> entry : sortedList) {
            String key = entry.getKey();
            System.out.println(key);
            List<int[]>songs= cateAndSongs.get(key);
            int f=songs.get(0)[0];
            int s=-1;
            if(songs.size()>=2){
                s=songs.get(1)[0];
            }
            answer.add(f);
            if(s!=-1){
                answer.add(s);
            }
           
        }
        System.out.println(answer);
        return answer;
    }

 


결과



gpt피드백

알고리즘

문제 요구사항을 그대로 잘 분리했어.

특히 자료구조를:

Map<String, Integer> cateAndCount
Map<String, List<int[]>> cateAndSongs

두 개로 나눈 것도 이해하기 쉬워.

복잡도도 충분해. 곡 수를 N이라고 하면 Map 구성은 O(N), 정렬들이 주로 비용을 차지해서 전체적으로 대략 O(N log N) 범위라고 보면 돼.

코드

가장 먼저 줄일 수 있는 건 cateAndCount 부분이야.

현재:

if (cateAndCount.containsKey(genres[i])) {
    int oc = cateAndCount.get(genres[i]);
    cateAndCount.put(genres[i], oc + plays[i]);
} else {
    cateAndCount.put(genres[i], plays[i]);
}

Java의 getOrDefault()를 쓰면:

cateAndCount.put(
    genres[i],
    cateAndCount.getOrDefault(genres[i], 0) + plays[i]
);

그리고 cateAndSongs도 computeIfAbsent()를 알면:

cateAndSongs
    .computeIfAbsent(genres[i], k -> new ArrayList<>())
    .add(new int[]{i, plays[i]});

그래서 처음 데이터 만드는 부분 전체가:

for (int i = 0; i < genres.length; i++) {
    cateAndCount.put(
        genres[i],
        cateAndCount.getOrDefault(genres[i], 0) + plays[i]
    );

    cateAndSongs
        .computeIfAbsent(genres[i], k -> new ArrayList<>())
        .add(new int[]{i, plays[i]});
}

로 줄어들어.

마지막도 지금:

int f = songs.get(0)[0];
int s = -1;

if (songs.size() >= 2) {
    s = songs.get(1)[0];
}

answer.add(f);

if (s != -1) {
    answer.add(s);
}

문제상 장르에는 최소 한 곡이 있으니까 그냥:

answer.add(songs.get(0)[0]);

if (songs.size() >= 2) {
    answer.add(songs.get(1)[0]);
}

면 충분해.

그리고 answer는 중간 삽입/삭제 없이 뒤에 계속 추가하니까:

List<Integer> answer = new ArrayList<>();

가 LinkedList보다 자연스러워.

알고리즘     : 좋음

자료구조 선택 : 좋음

정렬 조건     : 정확함

복잡도       : 문제없음

개선점       : getOrDefault / computeIfAbsent로 간결화

 
 
 

배운점과느낀점

-오랜만에 쉬운문제였다 자바프리셋은 참좋다