본문 바로가기
컴퓨터 공학/알고리즘

[알고리즘 / Kotlin] 프로그래머스 - 베스트앨범

by tempus 2021. 9. 24.
반응형

베스트 앨범(Level 3)

문제 설명

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


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

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


제한 조건

  • genres[i]는 고유번호가 i인 노래의 장르입니다.
  • plays[i]는 고유번호가 i인 노래가 재생된 횟수입니다.
  • genres와 plays의 길이는 같으며, 이는 1 이상 10,000 이하입니다.
  • 장르 종류는 100개 미만입니다.
  • 장르에 속한 곡이 하나라면, 하나의 곡만 선택합니다.
  • 모든 장르는 재생된 횟수가 다릅니다.

입출력 예


내 풀이

일단은 문제를 보고 sorting을 많이 해야겠다고 생각했습니다. 일단은 <고유번호, <장르, 재생 횟수>>인 HashMap을 만들어 그걸 통해 문제를 해결했습니다. 장르를 key로 하기에는 중복되어 원하는 구조의 자료가 나오지 않아서 고유번호를 key로 하여 해시를 생성하였습니다. (genresHash)


genresHash
genresHash

getMostGenresList() 함수를 만들어서 가장 많이 들은 장르 순서대로 저장하여 Array <String>을 리턴하게 하였습니다. (예 : ["pop", "classic"])


그러고 나서 genresHash에 필터링을 걸어서 해당 장르의 곡들만 뽑은 후 다음과 같은 순서로 조건을 걸어 정렬하였습니다.


  1. 재생 횟수가 많은 순으로 오름차순 정렬
  2. 고유 번호가 낮은 순으로 내림차순 정렬

1번 예제 같은 경우 다음과 같이 Hash가 정렬됩니다.

hash
hash

정렬 후 뒤에서 부터 2개까지만 고유 번호를 answer에 저장합니다. 이후 최종적으로 toIntArray()로 변환 후 정답을 반환합니다.


📝 코드

class Solution {
    fun solution(genres: Array<String>, plays: IntArray): IntArray {

     var answer = ArrayList<Int>()
     var genresHash = HashMap<Int, Map<String, Int>>()

     for (i in genres.indices) {
      genresHash[i] = mapOf(genres[i] to plays[i])
     }

     getMostGenresList(genres, plays).forEach {
         val hash = genresHash.filter { t-> t.value.keys.contains(it)}.toList().sortedWith(compareBy(     {it.second.values.toList()[0]} , {-it.first} ))
         var count = 0
         for(i in hash.size-1 downTo 0){
             if(count ==2)
                break
               answer.add(hash[i].first)
               count++
         }
     }   
        return answer.toIntArray()
    }


    fun getMostGenresList(genres: Array<String>, plays: IntArray) : Array<String> {

        val temp = HashMap<String, Int>()
        val g = ArrayList<String>()
        val arr : Array<String> = arrayOf()

        for(i in genres.indices){
            if(temp.containsKey(genres[i]))
                  temp[genres[i]] =temp[genres[i]]!!.plus(plays[i])
            else
                  temp[genres[i]] =plays[i]
        }

        temp.toList().sortedBy { it.second }.reversed().forEach {
            g.add(it.first)
        }

        return g.toArray(arr)
    }
}

다른 사람의 풀이

예제 1

class Solution {
    fun solution(genres: Array<String>, plays: IntArray): IntArray {
        return genres.indices.groupBy { genres[it] }
            .toList()
            .sortedByDescending { it.second.sumBy { plays[it] } }
            .map { it.second.sortedByDescending { plays[it] }.take(2) }
            .flatten()
            .toIntArray()
    }
}

genres.indices.groupBy { genres [it] }. toList(): 장르로 묶어주고 해당 고유번호를 리스트로 저장합니다.

[(classic, [0, 2, 3]), (pop, [1, 4])]


.sortedByDescending { it.second.sumBy { plays[it] } }: 재생횟수를 더하여 가장 많이 재생된 장르 순으로 정렬합니다. (내림차순)

[(pop, [1, 4]), (classic, [0, 2, 3])]


.map { it.second.sortedByDescending { plays[it] }.take(2) }: 고유 번호들을 내림 차순으로 정렬하고 앞에서 2개의 요소만 가져와서 리스트로 만들어줍니다.

[[4, 1], [3, 0]]


.flatten().toIntArray(): flatten()을 통해 2차원 배열을 1차원 배열로 만들어줍니다.

[4, 1, 3, 0]



소감

예제 코드를 보고 함수형 프로그래밍으로 잘 작성했다고 느꼈습니다. 하나하나 들여다보면 다 아는 함수들인데 이렇게 연속적으로 적용하는 것을 보고 스스로 아직 많이 멀었다고 느꼈습니다.


level 3 문제였지만 생각보다 쉽게 접근해서 풀었던 것 같습니다. 하면서 좀 더 쉽게 해결할 수 있었을 거 같은데 하는 부분이 있어서 아쉬웠습니다. 빠른 시일 내에 Kotlin 관련 강의를 하나 찾아서 들어야겠습니다.

반응형

댓글


loading