관리 메뉴

나만을 위한 블로그

[Algorithm] 프로그래머스 - 최빈값 구하기 (Kotlin) 본문

알고리즘 문제 풀이/프로그래머스

[Algorithm] 프로그래머스 - 최빈값 구하기 (Kotlin)

참깨빵위에참깨빵_ 2022. 12. 20. 19:42
728x90
반응형
최빈값은 주어진 값 중에서 가장 자주 나오는 값을 말한다. 정수 배열 array가 매개변수로 주어질 때 최빈값을 리턴하도록 solution()을 완성하라. 최빈값이 여러 개면 -1을 리턴한다

 

처음에 접근한 방법은 리스트를 돌면서 리스트 안의 요소들을 비교한 다음 겹치는 걸 출력하는 방식이었다. 여러 개가 나올 경우에 대한 예외처리를 짜던 중 코드가 많이 더러워지고 내가 원하는 결과가 나오지 않아서 다른 사람의 풀이를 확인해봤다.

 

https://velog.io/@anna_developer/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4%EC%B5%9C%EB%B9%88%EA%B0%92-%EA%B5%AC%ED%95%98%EA%B8%B0GG

 

프로그래머스_최빈값 구하기(GG)

프로그래머스_최빈값 구하기

velog.io

class Solution {
    fun solution(array: IntArray): Int {
        val list = array.groupBy { it }.entries.sortedByDescending { (key, value) -> value.size }
        return if (list.size > 1 && list[0].value.size == list[1].value.size) -1 else list[0].key
    }
}

 

파이썬만큼은 아니겠지만 코틀린도 너무 간결하다. 잘 사용하지 않았던 키워드와 함수가 있어서 각각을 확인해봤다. 먼저 groupBy {}다.

 

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/group-by.html

 

groupBy - Kotlin Programming Language

 

kotlinlang.org

각 요소에 적용된 지정된 keySelector 함수에서 반환된 키로 원래 배열의 요소를 그룹화하고, 각 그룹 키가 해당 요소 목록과 연결된 맵을 반환한다. 반환된 맵은 원래 배열에서 생성된 키의 항목 반복 순서를 유지한다

 

컬렉션에 붙여서 사용하면 컬렉션 안의 데이터들을 일정 기준으로 그룹화해서 Map 형태로 반환하는 함수다. 이 때 일정 기준이란 groupBy 뒤의 중괄호 블럭 안에 넣는 조건이다.

아래는 위 링크에서 제공하는 groupBy의 예제 코드 스니펫이다.

 

val words = listOf("a", "abc", "ab", "def", "abcd")
val byLength = words.groupBy { it.length }

println(byLength.keys) // [1, 3, 2, 4]
println(byLength.values) // [[a], [abc, def], [ab], [abcd]]

val mutableByLength: MutableMap<Int, MutableList<String>> = words.groupByTo(mutableMapOf()) { it.length }
// same content as in byLength map, but the map is mutable
// byLength 맵과 동일한 내용이지만 Map은 변경 가능하다
println("mutableByLength == byLength is ${mutableByLength == byLength}") // true

 

groupBy {} 안에 "it.length" 라는 조건을 넣었다. 문자열 길이를 기준으로 Map을 만들겠다는 뜻이다.

그래서 byLength를 출력하면 아래와 같이 출력된다.

 

val words = listOf("a", "abc", "ab", "def", "abcd")
val byLength = words.groupBy { it.length }

println(byLength)
// {1=[a], 3=[abc, def], 2=[ab], 4=[abcd]}

 

다시 정답 코드로 돌아간다. 내가 좀 더 보기 편하게 코드를 조금 바꿨다.

 

val list = array.groupBy { it }
    .entries.sortedByDescending { (key, value) ->
        value.size
    }
val a = if (list.size > 1 && list[0].value.size == list[1].value.size) {
    -1
} else {
    list[0].key
}

 

그 다음 entries 키워드를 사용하고 sortedByDescending {}을 사용하고 있다.

 

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/entries.html

 

entries - Kotlin Programming Language

 

kotlinlang.org

Map에 있는 모든 키밸류 쌍의 읽기 전용 Set를 반환한다

 

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/sorted-by-descending.html

 

sortedByDescending - Kotlin Programming Language

 

kotlinlang.org

지정된 선택기 함수(selector function)에서 반환된 값의 자연 정렬 순서에 따라 내림차순으로 정렬된 모든 요소 목록을 반환한다. 정렬이 안정적이다. 이는 동일한 요소가 정렬 후 서로 상대적인 순서를 유지함을 의미한다

 

groupBy {}로 만들어진 Map을 Set으로 반환한다. 그리고 해당 Set에서 리턴하는 값을 정렬한다는데 이 부분은 잘 모르겠어서 정답 코드 안의 sortedByDescending {} 안에 key, value를 각각 출력시켜서 확인해봤다.

 

 

??? 대체 어떻게 작동하는 건지 모르겠다. 그래도 Descending이 붙었다면 큰 숫자부터 작은 순서대로 정렬하는 것일테니 1을 하나 더 넣어서 실행시켜봤다.

 

 

3은 세 개, 1은 2개, 2와 4는 각 1개씩 있으니 정렬이 잘 된 것을 볼 수 있다.

entries가 Set이기 때문에 sortedByDescending {} 안에 (key, value)를 조건으로 넣고, value인 Map의 크기에 따라서 정렬된다.

 

그 다음 if로 조건을 걸어서, 리스트에 데이터가 2개 이상인지 확인하고 첫 번째와 두 번째 Map에 담긴 값의 크기가 같다면 -1, 아니면 첫 번째 Map의 key를 리턴한다. value는 위 사진에서 보다시피 Map 형태라서 value를 사용하면 문제의 입출력 예시와 다른 값을 리턴하게 되기 때문에 사용하면 안 된다.

 

val a = if (list.size > 1 && list[0].value.size == list[1].value.size) {
    -1
} else {
    list[0].key
}

 

2개 이상인지 확인하는 건 문제에서 요구했던 "최빈값이 여러 개면 -1을 리턴한다"를 위해서라고 생각된다.

리스트 크기를 확인하는 부분을 없애면 같은 숫자를 2개 이상 넣고 실행했을 때 에러가 발생한다.

반응형
Comments