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

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

class Solution {
    fun solution(array: IntArray): Int = array
            .groupBy{it}
            .map{it.value.size to it.key}
            .sortedByDescending { it.first }
            .let {
                if(it.size > 1 && it[0].first == it[1].first) -1 else it.first().second
            }
}

 

첫 번째 입출력 예를 통해 코드의 출력값을 흐름에 따라 알아보자. [1, 2, 3, 3, 3, 4]

 

우선 array를 가져와서 groupBy{ it } 으로 묶어준다.

 

groupBy 함수는 Map<K, List<V>> 형태의 결과를 반환한다.

즉, 키와 키에 해당하는 요소들을 리스트로 묶은 맵을 반환한다.

 

여기서는 it 자체로 키의 형태로 묶었기에 1,2,3,4를 키 형태로 가지고 그 키에 해당하는 원소들을 리스트에 넣는다.

{1=[1], 2=[2], 3=[3, 3, 3], 4=[4]}

 

이런 형태로 출력된다.

 

이후 .map을 통해 각 맵 컬렉션에 접근을 하고 우리는 지금 가장 많이 나온 value의 크기값을 알고 싶은 것이기에

it.value.size와 it.key를 to 를 통해 Pairing 시켜준다.

 

여기서 it.value.size 는 3을 예로 들자면 value인 3의 갯수이다. 그리고 key는 3이 될 것이다.

[(1, 1), (1, 2), (3, 3), (1, 4)]

 

이런 형태로 출력된다.

 

마찬가지로 우리는 가장 많이 나온 값에 관심이 있기에 it.value.size의 크기를 내림차순으로 해주기 위해 

.sortedByDescending { it.first } 을 이용한다. 여기서 it.first는 방금 전 pair로 묶어준 value.size다.

[(3, 3), (1, 1), (1, 2), (1, 4)]

 

이런 형태로 출력된다.

 

.let {
                 if(it.size > 1 && it[0].first == it[1].first) -1 else it.first().second
            }

 

이후 배열의 크기가 1 이상이면서 배열 0번째와 1번째의 first 즉 최빈값이 같다면 -1 을 내보내고 그 외에는 첫번째 배열의 second 즉 키 값을 내보낸다.

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

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

class Solution {
    fun solution(s: String, skip: String, index: Int): String {
        var answer: String = ""
        val alphabet = mutableListOf('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z')
        alphabet.removeAll { skip.contains(it) }
        answer = s.map {
            alphabet[(alphabet.indexOf(it) + index) % alphabet.size]
        }.joinToString("")
        return answer
    }
}

 

나는 이런식으로 알파벳을 모두 리스트에 넣고 removeAll을 통해서 삭제시킨 다음 시작했다.

근데 더 깔끔한 방법이 있었다.

 

class Solution {
    fun solution(s: String, skip: String, index: Int): String {
        val alphabet = ('a'..'z').filter{ it !in skip }
        return s.map { alphabet[(alphabet.indexOf(it) + index) % alphabet.size] }.joinToString("")
    }
}

 

저런식으로도 되는구나...

 

맵 안에를 설명하자면 간단하다.

 

s 안을 순회하며 it이 알파벳의 몇번째 인덱스에 속하는지 값과 건너뛰어야 하는 index값을 더하고 알파벳 배열인덱스를 초과할 수 있기 때문에 배열 사이즈로 나머지 연산을 해준다. 이후 리턴 타입이 스트링이므로 joinToString()을 통해 타입을 맞춰준다.

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

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

class Solution {
    fun solution(keymap: Array<String>, targets: Array<String>): IntArray =
        targets.map { str ->
            str.map { c -> keymap.map { it.indexOf(c) + 1 }
                .filterNot { it < 1 }
                .let { list ->
                    if (list.isEmpty()) -1
                    else list.minOf { it }
                }
            }.let { if ( it.contains(-1)) -1 else it.sum() }
        }.toIntArray()
}

 

좋은 코드를 짜려면 좋은 코드를 많이 보라는 말에 따라 오늘부터 코틀린스러운 문제 해결법에 집중해서 다른 분의 코드를 분석하고 내 것으로 만드는 과정을 시작해보려 한다. 위 코드를 통해 코틀린의 각종 확장함수와 함수 표현식을 알 수 있다.

 

위의 코드는 프로그래머스 최용건님의 코드이다. 안에 내용을 안과 밖을 구분해서 분석해보자.

targets.map { str ->
str.map { c -> keymap.map { it.indexOf(c) + 1 }
                .filterNot { it < 1 }
                .let { list ->
                    if (list.isEmpty()) -1
                    else list.minOf { it }
                }

분석해보자면 .map으로 타겟 배열을 스트링 그리고 문자로 나눠서 그 문자가 keymap배열의 몇번째 인덱스에 있는지 확인한다.

 

이 후 .filterNot을 통해 인덱스가 1보다 작은 것들은 빼고 배열형태로 반환한다.

 

그리고 리스트안에 만약 문자가 없으면 -1 을 보내고 여러개 있는데 그 중 우리는 최솟값을 찾는 것이기에 minOf를 통해 작은 값을 보낸다.

targets.map { str ->

				...
                
}.let{ if(it.contains(-1)) -1 else it.sum() }

 

나온 리스트안에 -1이 포함되어있으면 -1을 내보내고 아니라면 리스트안에 원소들을 모두 .sum()을 통해 합한다.

 

내가 생각하기엔 코틀린스럽다는 말이 이제 조금 와닿고 있다. 아무래도 이 문제에 최적화된 코드는 아니지만 문제가 좀 더 꼬여있을 때를 생각하면 좀 더 확장성 있게 잘 짠 코드인 것 같다.

 

처음에는 map으로 처리를 할까 하였으나 인덱스 값을 따져가며 하는게 비효율적이라 생각되어 고민을 좀 했다.

 

문자열 안에서 숫자는 냅두고 영단어만 숫자로 바꿀 순 없을까 하다가 찾은게 replace()

replace(바꿀녀석, 원하는결과) 이런식으로 쓰면 된다.

 

우선 코드를 보자.

 

class Solution {
    fun solution(s: String): Int {
        var answer : Int = 0
        val numArr = arrayOf("zero", "one", "two", "three", "four", "five", "six", "seven","eight", "nine")
        var temp = s
        for (i in 0 until numArr.size) {
            temp = temp.replace(numArr[i], i.toString())
        }
        answer = temp.toInt()
        return answer
    }
}

 

 

영단어를 배열에 넣어 반복문으로 해당하는 영단어가 있으면 그 영단어가 있었던 인덱스 값을 문자열값으로 넣어준다.

 

여기서 신경써줘야 할건 숫자를 배열에 순서대로 넣어준다는 것! one zero four two nine --- 이런식으로 넣으면 안된다. 또한 반복문의 조건식도 신경써서 넣어주어야한다.

 

배열을 잘 쓰면 까다로울 수 있는 문제도 쉽게 해결 가능하다는 걸 느낀 문제다.

 

 

+ Recent posts