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()을 통해 합한다.

 

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

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

 

프로그래머스

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

programmers.co.kr

 

 

이번 문제는 풀지 못했다... 가면 갈수록 어려워지고 있다. 다른 분의 코드를 보면서도 이해가 가지 않아 분석을 하면서 공부를하고 실력을 키우는 방향으로 잡았다.

 

import kotlin.math.min

class Solution {
    fun solution(X: String, Y: String): String {
        var answer: String = ""

        for (ch in (9 downTo 0).toList().map { it.toString() }) {
            answer += ch.repeat(
            min(
            	X.count { it.toString() == ch },
            	Y.count { it.toString() == ch }
               	)
           )
        }
        if (answer.isEmpty()) answer = "-1"
        if (answer.toList().distinct() == listOf('0')) answer = "0"

        return answer
    }
}

 

우선 이 코드의 방식은 9 부터 0 까지의 숫자로 X와 Y에서 등장하는 횟수를 구한 뒤 둘의 최솟값으로 반환하여 answer에 넣어주는 방식이다.

 

이제 한줄 한줄 분석해보자.

 

더보기

for (ch in (9 downTo 0).toList().map { it.toString() })

 

여기서는 9 downTo 0 을 통해 9 8 7 6 5 4 3 2 1의 범위를 가져오고

 

이 숫자들을 toList()를 통해 리스트 형태인 [ 9, 8, 7, 6, 5, 4, 3, 2, 1 ] 이 형식으로 만들어준다.

 

이후 X와 Y의 문자열 형태와 비교시켜주기 위해 .map{it.toString()} 각각의 숫자를 문자열형태로 변환해준다.

-> ['9', '8', '7', '6', '5', '4', '3', '2', '1', '0']

 

그리고 각 문자열 '9', '8', '7', '6', '5', '4', '3', '2', '1', '0' 을 차례대로 ch에 담아 준다.

더보기

answer += ch.repeat(코드내용)

여기가 처음 의아했던 부분이었다.

ch.repeat(n)은 앞에 변수인 ch를 n번 반복시켜주는 함수다.

이를 통해 repeat안에는 Int값이 들어올 것임을 알 수 있다.

아무튼 9부터 시작하여 0의 문자를 들어오는 정수 값에 따라 여러번 Answer에 넣어줄 수 있게 만들어주고 있다.

나머지는 뒤에 코드를 같이 보며 설명하겠다.

더보기

 

ch.repeat(min(X.count { it.toString() == ch }, Y.count { it.toString() == ch }))

 min() 함수는 ()안에 두 값을 비교해 최소값을 반환해주는 함수이다.

 중요한 건 그 안에 내용이다.

X.count{it.toString() == ch} Y.count{it.toString() == ch}

실제 함수가 돌아가는 예를 보자, X 가 "5525" Y가 "1255" 

처음 ch인 '9'가 들어온다. 그리고 X와 Y의 문자열을 순회하며 '9'와 같은 값이라면 카운트를 해주는 것이다.

X와 Y모두 '9', '8', '7', '6' 을 가지고 있지 않으므로 위의 ch.repeat에서 '9', '8', '7', '6' 은 들어가지 않는다.

하지만 '5' 차례일 때 부터는 다르다. X에서는 '5'가 3번이나 들어가고 Y는 2번 들어간다. 우리는 짝꿍일 경우에만 넣어주기에 2개만 넣어주어야 한다. 그걸 위해 min 함수를 통해 둘의 최소값인 Ycount=2를 반환해주는 것이다.

여기서 it.toString은 ch와 비교연산을 위해 타입을 맞춰주는 것이다. (원래 it 은char타입임)

더보기

        if (answer.isEmpty()) answer = "-1"
        if (answer.toList().distinct() == listOf('0')) answer = "0"

이 후 맞는 숫자가 없을 경우에는 answer에 어떤 ch도 들어가지 않기에 비어있으므로 -1 을 반환

그리고 X 가 "100" Y가 "10025"  와 같이 answer에 '0' 값이 두번 이상 있는 경우에 대비해 .distinct()로 중복을 제거해준 후 '0'만 있다면 answer에 '0'을 반환해주는 처리를 해준다. 

 

 

 

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

 

프로그래머스

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

programmers.co.kr

 

문제를 어떻게 풀어야 할지 막막한 문제였다,,, 결국에 힌트를 보게 되었고 괜찮은 코드를 보았다.

class Solution {
    fun solution(babbling: Array<String>): Int {
    	var answer: Int = 0

        for (i in babbling.indices) {
            if (babbling[i].contains("ayaaya") ||
                babbling[i].contains("yeye") ||
                babbling[i].contains("woowoo") ||
                babbling[i].contains("mama"))
            {
                continue
            }
            babbling[i] = babbling[i].replace("aya", " ")
            babbling[i] = babbling[i].replace("ye", " ")
            babbling[i] = babbling[i].replace("woo", " ")
            babbling[i] = babbling[i].replace("ma", " ")
            babbling[i] = babbling[i].replace(" ", "")

            if (babbling[i].isEmpty()) answer++
        }
        return answer
    }
}

 

보다보니 호텔 예약 프로그램을 코딩할 때 문자열에 숫자를 포함시키지 않기 위해서 Regex라는 정규 표현식을 사용했던 기억이 났다. 그걸 적용해볼 수 있겠다. 생각이 들어 적용시켜보았다. but 역시 나만 그렇게 생각한게 아니였고 이미 획기적으로 코드량을 줄인 코드가 있었다. 한번 같이 보면서 regex 정규 표현식을 공부해보면 좋을 것 같다.

 

class Solution {
    fun solution(babbling: Array<String>): Int {
        var answer: Int = 0
        var regexA = "aya|ye|woo|ma".toRegex()
        var regexB = "ayaaya|yeye|woowoo|mama".toRegex()
        answer = babbling.map{it.replace(regexB,"x")}.map{it.replace(regexA,"")}.count{it.isEmpty()}
        return answer
    }
}

 

이렇게 바꾸니 속도도 이전 코드보다 약 20%가량 더 빨라진 것 같다.

 

정규 표현식(Regex)

-> Regular Expression의 약자로 특정한 규칙을 가진 문자열의 집합을 표현하기 위해 사용하는 형식 언어

이해가 확 와닿지는 않는다,,, 쉽게 말하자면 주로 어떤 문자열에서 특정한 조건의 문자열을 찾고 싶을 때 쓴다.

예를 들어서 회원가입이나 로그인을 받을 때 아이디나 비밀번호에서 최소 10자리에 숫자, 문자, 특수문자 각각 몇개씩 포함해서 작성해라! 에 따른 유효성 검사를 할 때도 사용가능하고 위에 문제처럼 해당 문자를 찾아 원하는 처리를 하고 싶을 때 자주 사용된다.

 

정규 표현식의 내용을 정리하려 했으나 그것 보다는 이해를 위한 영상 추천과 잘 정리해둔 블로그를 남겨 놓는게 더 좋을 것 같다는 생각이 들어 밑에 남겨두겠다.

 

정규 표현식 완전 처음이라면 영상

https://youtu.be/t3M6toIflyQ?si=7C24u9qSMgDXZvpQ

 

알고 있지만 문법을 확인하고 싶다면 밑에 블로그

https://yoon-dailylife.tistory.com/113

https://school.programmers.co.kr/learn/courses/30/lessons/77484?language=kotlin

 

프로그래머스

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

programmers.co.kr

 

 

class Solution {
    fun solution(lottos: IntArray, win_nums: IntArray): IntArray {
        var answer: IntArray = intArrayOf()
        var countA = 0
        var countB = 0
        var bestRank = 0
        var worstRank = 0
        lottos.map {
            if(win_nums.contains(it)) {
                countA++
            }
            if(it == 0) {
                countB++
            }
        }
        when(countA){
            6 -> worstRank = 1
            5 -> worstRank = 2
            4 -> worstRank = 3
            3 -> worstRank = 4
            2 -> worstRank = 5
            1 -> worstRank = 6
            0 -> worstRank = 6
        }
        when(countA  + countB){
            6 -> bestRank = 1
            5 -> bestRank = 2
            4 -> bestRank = 3
            3 -> bestRank = 4
            2 -> bestRank = 5
            1 -> bestRank = 6
            0 -> bestRank = 6
        }
        answer += bestRank
        answer += worstRank
        return answer
    }
}

 

크게 생각하지 않고 순수하게 적어봤다..

 

 

속도가 조금 아쉽다..

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

 

프로그래머스

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

programmers.co.kr

class Solution {
    fun solution(number: Int, limit: Int, power: Int): Int {
        var answer: Int = 0
        var factorList = arrayListOf<Int>()
        var count = 0
        for(i in 1..number){
            for(j in 1..i){
                if(i % j ==0){
                    count++
                }
            }
            factorList += count
            count = 0
        }
        factorList.map {
            if(it > limit){
                answer += power
            }
            else answer += it
        }
        return answer
    }
}

 

로직은 간단해서 그냥 바로바로 쳤더니 역시 생각없이 친 코드는 시간초과다,,ㅎㅎ

 

 

약수를 구하는 과정을 좀 단순하게 해야할 것 같다. 

import kotlin.math.sqrt
class Solution {
    fun solution(number: Int, limit: Int, power: Int): Int {
        var answer: Int = 0
        var count = 0
        for(i in 1..number){
            var sqrtNum = sqrt(i.toDouble()).toInt()
            var count = 0
            for(j in 1..sqrtNum){
                if(i%j==0){
                    if (i / j == j) count += 1
                    if (i / j != j) count += 2
                }
            }
            if(count>limit) answer+=power
            else answer+=count
        }
        return answer
    }
}

 

약수를 구하는 방법을 찾아보니 제곱근을 통해서 시간복잡도를 조금 해결해줄 수 있는 방법을 찾았다.

만약 100의 약수를 찾는다면 100의 제곱근인 10까지의 약수[1,2,5,10]를 구한 후 100을 10까지의 약수로 나눠진 값을 합치고 중복된 숫자를 Set나 다른 방법으로 제거하고 count해주면 된다.

 

하지만 나는 조금 더 간결하게 해봤다. 결국에 1을 제외하고 나머지 약수에서 결국엔 2개씩의 카운트가 나오기에 위의 코드처럼 짰다.

 

통과!

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

 

프로그래머스

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

programmers.co.kr

 

 

class Solution {
    fun solution(n: Int, m: Int, section: IntArray): Int {
        var answer: Int = 0
        var max = 0
        if(m == 1) {
            answer = section.size
        }
        else {
            for(i in 0 until section.size){
                if(section[i] < max){
                    continue
                }
                answer++
                max = section[i] + m
            }
        }
        return answer
    }
}

 

처음에 answer 값에 1을 먼저두고 max에 m값을 넣어놓고 풀었다.

예시 테스트는 통과했으나 채점테스트에서 4개의 반례가 나왔다. 찾아봐도 반례를 못찾아 조원분께 도움을 요청드렸다.

 

알고보니 같은 문제에서 테스트 값 5, 2, [1,2,5] 로 꽤나 고생을 하셨다고 하셨다. 한번 테스트값으로 추가해보라는 말씀대로 추가해서 보니 정말 내 코드의 반례가 되는 예시였다. 천천히 코드에 넣어서 분석해보니 for문안에 if문에서 section[i]값과 max값이 같을 때 일어나는 문제였다. 

 

answer 초기값 0 max도 초기값 0 으로 실행하면 정말 쉽게 풀어지는 문제였다.

 

도움을 요청하고 함께 문제점을 논의하는 과정이 정말 중요하다는 이야기를 들을 때면  "그래 그렇지" 라는 생각만 들었다. 하지만 사실 실제로 그렇게 하는 것은 보기보다 어려운 문제인 것 같다..

 

살면서 어려움에 봉착했을 때 다른 사람에게 도움을 구해야 겠다는 생각과 행동은 도움을 구해본 경험이 중요한 것 같다.

 

도움을 요청하려는 생각이 나의 약점을 노출시키고 초라하게 만들 것이라고 느껴왔던건지 나는 살면서 도움을 많이 요청한 경험이 많이 없었다. (<- 이런 사람 특: 알게모르게 도움 많이 받음,,ㅎㅎ)

 

하지만 내일배움캠프를 하면서 정말 적극적으로 모르는 것에 있어서 팀원들 그리고 튜터분들께 질문하고 도움을 요청하면서 느낀 점은 도움을 요청하는 것이 내 생각과 다르게 나를 더 빠르게 성장시키고 발전시키고 있다는 것이다.

 

도움을 요청하기 전에 내가 어떤 부분에서 어려움을 느끼고 있는지 정확히 인지하고 있어야 하는 부분에서 스스로 배우는 것도 많았고 모르는 부분에 대한 답변을 받을 때 모르는 부분을 포함한 그 외 것들에서도 배우는게 있었다.

 

이번에 정말 이건 반례가 없다!!! 프로그래머스 프로그램에서 문제점을 발견했다!!! 라고 생각했던 나를 다시 되돌아보게 된 문제였다.

3조 경식님께 감사의 말씀 올립니다ㅎㅎ

+ Recent posts