본문 바로가기
Language/Java

[Programmers | Java | 연습문제 풀이] 베스트앨범 - Solution with HashMap & 정렬

by ㅇ달빛천사ㅇ 2024. 12. 2.
728x90

 

코딩테스트 연습 / 해시 / 베스트앨범

 

📀 베스트앨범

🏷️ 관련 주제 : 해시 HashMap 정렬

 


💡 Solution With HashMap & 정렬

import java.util.HashMap;
import java.util.ArrayList;
import java.util.stream.IntStream;

class Solution {
    public int[] solution(String[] genres, int[] plays) {
        int[] answer = {};
        int total_songs = genres.length;
        HashMap<String, Integer> total_plays_of_song = new HashMap<>();
        HashMap<String, Integer> genre_song_count = new HashMap<>();
        
        IntStream.range(0, total_songs).forEach(i -> {
            String genre = genres[i];
            Integer play = plays[i];
            
            if (total_plays_of_song.containsKey(genre)) {
                Integer total_plays = total_plays_of_song.get(genre);
                total_plays_of_song.put(genre, total_plays + play);
                return;
            }
            
            total_plays_of_song.put(genre, play);
        });
        
        ArrayList<Integer> songList = new ArrayList<>();
        IntStream.range(0, total_songs)
                    .boxed()
                    .sorted((x, y) -> {
                        String genreX = genres[x];
                        String genreY = genres[y];

                        if (!genreX.equals(genreY)) {
                            return total_plays_of_song.get(genreY) - total_plays_of_song.get(genreX);
                        }

                        return plays[y] - plays[x];
                    })
                    .forEachOrdered(x -> {
                        String genreX = genres[x];
                        
                        if (genre_song_count.containsKey(genreX)) {
                            Integer song_cnt = genre_song_count.get(genreX);
                            
                            if (song_cnt == 1) {
                                genre_song_count.put(genreX, song_cnt + 1);
                                songList.add(x);
                            }
                            
                            return;
                        }
                        
                        genre_song_count.put(genreX, 1);
                        songList.add(x);
                    });
        
        
        answer = songList.stream()
                    .mapToInt(i -> i)
                    .toArray();
        return answer;
    }
}


📗 참고 자료


🖋️ 풀이 과정

 

처음 문제를 풀 때, 가장 많이 재생된 노래를 "2개씩" 모은다는 조건을 빼 먹어서 문제가 왜 이렇게 쉽지?

라고 생각했는데 나중에서야 그 조건을 보고 코드를 다시 작성해야했다.

문제를 찬찬히 읽고, 주석 작성하기!

실천이 잘 안되는데 내일부터는 꼭 해 보아야겠다.

문제 유형에 해시라고 되어 있어서 HashMap으로 문제를 해결하였다.

  • 키(Key): 장르
  • 값(Value): 총 재생 횟수

 

1. 각 장르별 재생 횟수를 모두 더하기

int total_songs = genres.length;
HashMap<String, Integer> total_plays_of_song = new HashMap<>();

IntStream.range(0, total_songs).forEach(i -> {
    String genre = genres[i];
    Integer play = plays[i];

    if (total_plays_of_song.containsKey(genre)) {
        Integer total_plays = total_plays_of_song.get(genre);
        total_plays_of_song.put(genre, total_plays + play);
        return;
    }

    total_plays_of_song.put(genre, play);
});

 

2. 정렬 및 2번째 이후 순위의 곡을 제외

int total_songs = genres.length;
HashMap<String, Integer> genre_song_count = new HashMap<>();


IntStream.range(0, total_songs)
            .boxed()
            .sorted((x, y) -> {
                String genreX = genres[x];
                String genreY = genres[y];

                if (!genreX.equals(genreY)) {
                    return total_plays_of_song.get(genreY) - total_plays_of_song.get(genreX);
                }

                return plays[y] - plays[x];
            })
            .forEachOrdered(x -> {
                String genreX = genres[x];

                if (genre_song_count.containsKey(genreX)) {
                    Integer song_cnt = genre_song_count.get(genreX);

                    if (song_cnt == 1) {
                        genre_song_count.put(genreX, song_cnt + 1);
                        songList.add(x);
                    }

                    return;
                }

                genre_song_count.put(genreX, 1);
                songList.add(x);
            });

 

좀 더 구체적으로는

 

2-1. 정렬

두 곡을 서로 비교하여 서로 다른 장르이면 장르별 총 재생 횟수 기준 내림차순 정렬을 적용하였다.

장르 비교는 Objects.equals()를 사용할지, 그냥 equals()를 사용할 지 고민하다가

장르가 null이 나오는 경우가 없어서 그냥 equals()로 비교해 주었다.

if (!genreX.equals(genreY)) {
    return total_plays_of_song.get(genreY) - total_plays_of_song.get(genreX);
}

 

서로 같은 장르이면 각 노래의 재생 횟수를 기준으로 내림차순 정렬을 적용하였다.

return plays[y] - plays[x];

 

 

2-2. 각 장르별 2곡만 선정

병렬 스트림을 사용하지 않아서 forEach()문을 써도 되는데
인터넷 검색 결과로는 직렬 스트림에서 forEach()와 forEachOrdered()가 동일하다고 하는데
결과는 forEachOrdered()가 더 빨라서 forEachOrdered()를 사용하였다.

 

각 인덱스의 노래를 songList에 추가할 때마다 HashMap에서 장르별로 숫자를 세서

해당 장르의 노래가 이미 2곡 추가되어 있으면 songList에 곡이 추가되지 않도록 하였다.

HashMap<String, Integer> genre_song_count = new HashMap<>();
ArrayList<Integer> songList = new ArrayList<>();

// 코드 생략

.forEachOrdered(x -> {
    String genreX = genres[x];

    if (genre_song_count.containsKey(genreX)) {  // HashMap에 해당 장르가 있는 경우
        Integer song_cnt = genre_song_count.get(genreX);

        if (song_cnt == 1) {  // songList에 추가된 곡이 1곡인 경우, 현재 곡을 songList에 추가
            genre_song_count.put(genreX, song_cnt + 1);
            songList.add(x);
        }

        return;  // songList에 추가된 곡이 2곡 이상인 경우, 현재 곡을 추가X
    }

    genre_song_count.put(genreX, 1);  // HashMap에 해당 장르가 없는 경우
    songList.add(x);
});

 

3. songList를 int[]로 변환하여 반환

int[] answer = {};

answer = songList.stream()
            .mapToInt(i -> i)
            .toArray();
return answer;
728x90