Algorithm/kotlin

[프로그래머스/Kotlin] 체육복 (Lv. 1)

나연쓰 2024. 4. 3. 12:27

문제

점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 예를 들어, 4번 학생은 3번 학생이나 5번 학생에게만 체육복을 빌려줄 수 있습니다. 체육복이 없으면 수업을 들을 수 없기 때문에 체육복을 적절히 빌려 최대한 많은 학생이 체육수업을 들어야 합니다.

전체 학생의 수 n, 체육복을 도난당한 학생들의 번호가 담긴 배열 lost, 여벌의 체육복을 가져온 학생들의 번호가 담긴 배열 reserve가 매개변수로 주어질 때, 체육수업을 들을 수 있는 학생의 최댓값을 return 하도록 solution 함수를 작성해주세요.

 

제한사항

  • 전체 학생의 수는 2명 이상 30명 이하입니다.
  • 체육복을 도난당한 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.
  • 여벌의 체육복을 가져온 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.
  • 여벌 체육복이 있는 학생만 다른 학생에게 체육복을 빌려줄 수 있습니다.
  • 여벌 체육복을 가져온 학생이 체육복을 도난당했을 수 있습니다. 이때 이 학생은 체육복을 하나만 도난당했다고 가정하며, 남은 체육복이 하나이기에 다른 학생에게는 체육복을 빌려줄 수 없습니다.

 

입출력 예

 

풀이방법

1. 전체의 학생 수에서 체육복을 도난 당한 학생 수를 빼서 현재 체육복을 가지고 있는 학생 수를 구한다.

var answer = n - lost.size

 

2. 체육복을 도난 당한 학생 수 배열을 오름차순 정렬한다.

var sortedLost = lost.sorted()

 

3. map을 만들어서 여벌 체육복이 있는 학생들만큼 반복문을 돌며 현재 가지고 있는 여벌 체육복의 수를 value에 넣는다.

var map = HashMap<Int, Int>()
for(r in reserve){
    map[r] = map.getOrDefault(r, 0) + 1
}
for(e in 0..n+1){
    map[e] = map.getOrDefault(e, 0)
}

 

4. "여벌 체육복을 가져온 학생이 체육복을 도난당했을 수 있습니다."라고 했기 때문에 sortedLost에서 현재 내가 체육복을 도난 당했는데 여벌 체육복이 있는지(MeList) , 체육복을 도난 당했는데 여벌 체육복이 없는지(noClothesList) 를 각각 배열을 만들어서 넣어줬다.

그리고 '체육복을 도난 당했는데 여벌 체육복이 있다'면 내가 체육복을 입어야하기 때문에 map에서 내가 갖고 있는 체육복 - 1 을 해준다. 그리고 answer+1을 한다.

마지막으로 '체육복을 도난 당했는데 여벌 체육복이 없는' 학생들을 상대로 체육복을 빌릴 수 있는지 없는지 체크해야하기 때문에 sortedLost에 noClothesList를 할당한다.

val noClothesList = sortedLost.filter { !reserve.contains(it) }
val MeList = sortedLost.filter { reserve.contains(it) }

for(m in MeList){
    map[m] = map.getOrDefault(m, 0) - 1
    answer++
}
sortedLost = noClothesList

 

5. sortedLost를 반복하며 만약 현재 학생의 앞 학생이 체육복을 가지고 있다면(map[it-1]!! > 0) 그 학생의 체육복 수 - 1을 하고 answer를 증가시킨다.

만약 현재 학생의 뒷 학생이 체육복을 가지고 있다면(map[it+1]!! > 0) 그 학생의 체육복 수 -1을 하고 answer를 증가시킨다.

sortedLost.forEach {
    if(map[it-1]!! > 0){
        map[it-1] = map.getOrDefault(it-1, 0) - 1
        answer++
    }else if(map[it+1]!! > 0){
        map[it+1] = map.getOrDefault(it+1, 0) - 1
        answer++
    }
}

 

주의할 점

내가 생각했을 때 이 문제에서 조심해야할 부분이 몇 가지 있다.

1. (풀이방법 5번)

lost를 오름차순 정렬로 했다면 조건문을 적을 때 무조건 앞 사람 부터 체크하고, 그 다음에 뒷 사람을 체크해줘야한다.

만약 이렇게 하지 않는다면 아래의 예시에서 반례가 된다.

n = 5
lost = [4, 2]
resverse = [3, 5]
return = 5

만약 아래와 같이 체육복을 입은 학생 수가 오름차순 정렬이 아닌 마구잡이로 되어있는 상태에서 체육복을 빌려줄 수 있는지 체크한다면

4번 학생은 3번 학생에게 빌릴 것이다. 그리고 2번 학생은 1 or 3번 학생에게 빌려야되는데 빌릴 수 없으므로 체육 수업에 참여할 수 있는 학생은 총 4명이다.

 

하지만 여기서 2,4로 오름차순 정렬한다면

2번 학생이 3번 학생에게, 4번 학생이 5번 학생에게 체육복을 빌려서 총 5명의 학생이 체육 수업에 참여할 수 있다.

 

정렬을 하지 않고도 어떻게든 풀 수 있겠지만 그럼 코드가 복잡해지고 무조건 어떤 반례에 걸릴 것 같아서 위와 같이 정렬을 하면 좋을 것 같다.

 

 

코드

class Solution {
    fun solution(n: Int, lost: IntArray, reserve: IntArray): Int {
        var answer = n - lost.size
        
        var sortedLost = lost.sorted()
        
        //체육복을 가지고 있는지 없는지
        var map = HashMap<Int, Int>()
        for(r in reserve){
            map[r] = map.getOrDefault(r, 0) + 1
        }
        for(e in 0..n+1){
            map[e] = map.getOrDefault(e, 0)
        }
        
        //여벌 체육복을 가져온 학생이 체육복 도난당했을 경우 처리
        val noClothesList = sortedLost.filter { !reserve.contains(it) }
        val MeList = sortedLost.filter { reserve.contains(it) }

        for(m in MeList){
            map[m] = map.getOrDefault(m, 0) - 1
            answer++
        }
        sortedLost = noClothesList
        
        //체육복을 빌릴 수 있는지 체크
        sortedLost.forEach {
            if(map[it-1]!! > 0){
                map[it-1] = map.getOrDefault(it-1, 0) - 1
                answer++
            }else if(map[it+1]!! > 0){
                map[it+1] = map.getOrDefault(it+1, 0) - 1
                answer++
            }
        }
        return answer
    }
}

 

느낀점

너무 고난과 고통을 겪었던 문제였다. 생각할게 너무 많았던 문제 .. 나만 그랬나 ? 무려 Lv.1이긴 한데 .. ^^

아직 코틀린 문법이 익숙하지 않다는 것을 느꼈고 코틀린 만의 장점인 filter와 같은 함수를 적극 사용해야겠다.

 

 

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

 

프로그래머스

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

programmers.co.kr