[java] 프로그래머스 - 베스트앨범

2 분 소요

업데이트:

문제

프로그래머스-베스트앨범
장르와 재생횟수를 가지고 장르별로 가장 많이 재생된 노래를 두 곡씩 모아 인덱스를 리턴하는 문제

장르 총 재생 수, 각 장르 내의 재생 횟수 많은 순으로 2곡씩 뽑아 앨범을 만든다.

  • 예시
    장르 : 클래식, 팝, 클래식, 클래식, 팝
    재생 횟수 : 500, 600, 150, 800, 2500
    클래식은 총 1450회 재생, 팝은 총 3100회 재생
    -> 팝먼저 수록, 팝 중에서 재생 수가 많은 2곡 + 클래식 중에서 재생수가 많은 2곡
    4,1,3,0 순으로 앨범 생성
  • 주의
    • 장르 속한 곡이 1개라면 1개 곡만 선택
    • 모든 장르는 재생 횟수가 다름

풀이

1) 장르, 장르 총 재생 횟수, 곡(song) 리스트를 재생횟수 순으로 저장하는 Songs클래스 생성, Songs객체 하위로 들어갈 인덱스와 재생횟수를 저장하는 song클래스 생성

2) 장르와 인덱스를 담을 해쉬맵 생성 (keys),
Songs객체를 담는 어레이리스트 생성 (songs)

3) 반복문 돌면서 입력받은 곡 정보를 순환
3-1) 맵에 해당 장르가 있으면 songs의 인덱스번째 객체에 재생횟수 추가하고, 하위 곡으로 추가
3-2) 없는 경우, keys에 장르 이름, songs의 다음 인덱스로 put해줌
마찬가지로 songs의 인덱스번째에 객체 생성 후 재생횟수와 장르 이름을 담음

4) 반복문 순환 후 songs의 전체 재생횟수에 따라 정렬한다

5) songs를 돌면서 하위곡이 1개 이하면 정답에 1개 곡의 인덱스 추가
2개 이상이면 재생횟수 순으로 상위 2개 곡의 인덱스를 정답에 추가

소스코드

import java.util.*;
class Solution {
   public int[] solution(String[] genres, int[] plays) {
		int t = 0;
		ArrayList<Songs> songs = new ArrayList<>();
		HashMap<String, Integer> keys = new HashMap<>();
		for (int i = 0; i < genres.length; i++) {
			if (keys.containsKey(genres[i])) {
				int idx = keys.get(genres[i]);
				Songs s = songs.get(idx);
				s.cnt += plays[i];
				s.songList.add(new song(i, plays[i]));

			} else {
				keys.put(genres[i], songs.size());
				Songs s = new Songs(genres[i], plays[i]);
				s.songList.add(new song(i, plays[i]));
				songs.add(s);

			}
		}
		songs.sort(new Comparator<Songs>() {

			@Override
			public int compare(Songs o1, Songs o2) {
				// TODO Auto-generated method stub
				return o2.cnt - o1.cnt;
			}
		});
		for (int i = 0; i < songs.size(); i++) {
			if(songs.get(i).songList.size()<2) {
				t+=songs.get(i).songList.size();
			}else {
				t+=2;
			}
		}
		int answer[] = new int[t];
		int idx = 0;
		for (int i = 0; i < songs.size(); i++) {
			int size = songs.get(i).songList.size();
			if(size>2)
				size = 2;
			for (int j = 0; j < size; j++) {
				answer[idx++] = songs.get(i).songList.poll().idx;
			}
		}
		return answer;
	}
}

class Songs {
	String genre;
	int cnt;
	PriorityQueue<song> songList = new PriorityQueue<>();

	public Songs(String genre, int cnt) {
		super();
		this.genre = genre;
		this.cnt = cnt;
	}

	@Override
	public String toString() {
		return "Songs [genre=" + genre + ", cnt=" + cnt + ", " + songList;
	}

}

class song implements Comparable<song> {
	int idx;
	int plays;

	public song(int idx, int plays) {
		super();
		this.idx = idx;
		this.plays = plays;
	}

	@Override
	public int compareTo(song o) {
		// TODO Auto-generated method stub
		if (this.plays == o.plays) {
			return this.idx - o.idx;
		}
		return o.plays - this.plays;
	}

}

다른 사람의 코드

IntStream은 무엇일까..
굉장히 파이써닉한 코드같은 자바코드다
댓글 중에 실행시간이 오래걸려 비효율적이라고 하지만
이런식으로 코드를 짤 수 있다는 것을 공부하는데 좋은 코드라고 했다.
나름 자바를 배웠는데도 무슨 의미인지 코드가 어렵다 ㅠㅠ

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Solution {
  public class Music implements Comparable<Music>{

    private int played;
    private int id;
    private String genre;

    public Music(String genre, int played, int id) {
      this.genre = genre; 
      this.played = played;
      this.id = id;
    }

    @Override
    public int compareTo(Music other) {
      if(this.played == other.played) return this.id - other.id;
      return other.played - this.played;
    }

    public String getGenre() {return genre;}
  }

  public int[] solution(String[] genres, int[] plays) {
    return IntStream.range(0, genres.length)
    .mapToObj(i -> new Music(genres[i], plays[i], i))
    .collect(Collectors.groupingBy(Music::getGenre))
    .entrySet().stream()
    .sorted((a, b) -> sum(b.getValue()) - sum(a.getValue()))
    .flatMap(x->x.getValue().stream().sorted().limit(2))
    .mapToInt(x->x.id).toArray();
  }

  private int sum(List<Music> value) {
    int answer = 0;
    for (Music music : value) {
      answer+=music.played;
    }
    return answer;
  }
}

댓글남기기