[프로그래머스] 콜라 문제

neoneoneo·2024년 3월 6일
0

kotlin

목록 보기
22/49

문제

콜라를 받기 위해 마트에 주어야 하는 병 수 a, 빈 병 a개를 가져다 주면 마트가 주는 콜라 병 수 b, 상빈이가 가지고 있는 빈 병의 개수 n이 매개변수로 주어집니다. 상빈이가 받을 수 있는 콜라의 병 수를 return 하도록 solution 함수를 작성해주세요.

나의 풀이

class Solution {
    fun solution(a: Int, b: Int, n: Int): Int {
        var answer: Int = 0    
        var sbBottles: Int = n
        while ( sbBottles >= a ) {
            val temp = sbBottles / a * b
            answer += temp
            sbBottles = temp + (sbBottles % a)
        }     
        return answer
    }
}
  • 바꿀 수 있는 콜라의 개수(sbBottles)가 마트에서 받아주는 콜라 개수(a)보다 크거나 같아야지만 계산이 가능해지므로, while문의 조건에 명세한다.
  • while문 안에는 임시 변수를 두어 바꿀 수 있는 콜라 개수를 저장해두고, answer에 누적한다.
    • while문 안에서 계속해서 초기화 선언되므로 불변 변수(val)로 선언한다. - 팀원의 코드를 참고함!
  • 그리고나서 바꿀 수 있는 콜라 개수를 갱신하는데, 이미 교환한 콜라 개수(temp)와 개수가 모자라 바꾸지 못했던 콜라 개수(sbBottles % a)를 더하여 계산한다.

위 코드는 팀원들과 데일리 알고리즘 리뷰를 통해서 힌트를 얻어 작성한 것이고.. 아래는 나 혼자 삽질한 내용이다. 결국 내가 접근한 방식에 대해 스스로 답을 구하지는 못하였다.

나의 풀이 우여곡절쑈..

첫 번째 시도 : 무한반복문

class Solution {
    fun solution(a: Int, b: Int, n: Int): Int {
        var answer: Int = 0
        var remainder: Int = 0
        var sbBottles: Int = n       
        // (n / a) * b = n 계산식을 반복
        // 20 / 2 * 1 = 10
        // 10 / 2 * 1 = 5
        // 5  / 2 * 1 = 2 (나머지 1 적립)
        // 2  / 2 * 1 = 1 (몫이 1일 때 적립)
        // 2  / 2 * 1 = 1 (나머지가 0이고 몫이 1일 때 종료)       
        while (true) {            
            if ( sbBottles % a == 0 ) { // 나머지가 없을 때
                println("나머지가 없을 때 진입")
                sbBottles = (sbBottles / a) * b 
                println("다음에 바꿀 수 있는 콜라병은 $sbBottles")
            } else if ( sbBottles % a > 0 ) { // 나머지가 있을 때
                println("나머지가 있을 때 진입")
                remainder = sbBottles % a // 나머지는 적립
                sbBottles = (sbBottles / a) * b // 몫은 사용
                println("다음에 바꿀 수 있는 콜라병은 $sbBottles , 적립된 나머지는 $remainder")
            }
            else if ( remainder > 0 && sbBottles == 1) { // 나머지가 있고 몫이 1일 때
                println("나머지 있고 몫이 1일 때 진입")
                sbBottles += remainder
                sbBottles = (sbBottles / a) * b
            }            
            answer += sbBottles            
            if ( remainder == 0 && sbBottles == 0 ) break // 나머지가 0이고 몫이 1이면 종료
        }        
        return answer
    }
}
  • 결국 답을 구하지 못 한 코드이다.
  • while(true)로 두어 계속해서 반복하다가 특정 조건이 되면 break로 빠져나오게 하였다.
  • 이렇게 코드를 돌리면 무한반복의 굴레에 빠져 답을 구할 수가 없었다(사실 어떻게 또 수정해서 test case 2개에 대해서는 답을 구할 수는 있었지만, 막상 제출하면 전부 fail을 받았다.)
  • 똑같은 계산식을 반복해야 하고, 특정 조건이 생기면 다른 계산식을 쓰자! 라는 생각에 처음에 이렇게 접근했는데, 점점 추가할 조건이 많아져 코드가 길어지고 복잡해졌다.
  • 여러모로 문제가 많았던 코드이고, 아 이건 아니다 싶어서 생각해낸게 재귀함수인데...

두 번째 시도 : 재귀함수

class Solution {
    fun solution(a: Int, b: Int, n: Int): Int {
        return sbb(a, b, n, 0)
    }
    // (n / a * b) + (n % a) = n 바꿀 수 있는 콜라 개수
    tailrec fun sbb(a: Int, b: Int, n: Int, acc: Int): Int {
        return if (a > n) {
            acc // 종료 조건: a > n 이면 적립된 값을 반환
        } else {
            sbb(a, b, (n / a * b) + (n % a), acc + ((n / a * b) + (n % a))
        }
    }
}
  • 예전부터 재귀함수를 응용해보고 싶었고, 마침 반복되는 계산식을 함수로 빼내어 처리하면 되겠다 싶어서 써봤다.
  • 코드에 에러는 없었지만 정확한 답이 나오지 않았다. 계산식이 잘 못되었기 때문이다.
  • ChatGPT에게 재귀함수를 써서 문제를 풀어달라고 하니 아래와 같이 답을 주지만 코드를 돌려보면 제대로된 답을 구하지 못한다.
    • 여기도 계산식 부분이 잘 못된 것 같다. 저렇게 한줄짜리 계산식을 사용하지 않고, 나의 풀이처럼 풀어서(?) 코드를 쓴 다음 재귀함수 처리하면 정상 작동 할 것 같다. 다만, 이렇게 돌이켜보니 이 문제를 풀 때 재귀함수까지 쓰는건 좀 오바인 것 같다.
class Solution {
    fun solution(a: Int, b: Int, n: Int): Int {
        var answer: Int = 0
        val result = buyCola(a, b, n)
        answer = result
        return answer
    }
    tailrec fun buyCola(a: Int, b: Int, n: Int, total: Int = 0): Int {
        return if (n < a) total
        else buyCola(a, b, (n / a) * b + n % a, total + n / a)
    }
}

고수의 풀이

이런 것도 있더라..

class Solution {
    fun solution(a: Int, b: Int, n: Int): Int {
        return (if (n > b) n - b else 0) / (a - b) * b
    }
}
  • 계산식은 이렇게 짜는거더라..

배운점

  • 역시 기초가 탄탄해야한다. 괜히 재귀함수 쓴다, 안써봤던 함수들 가져다 쓴다고 설치기 전에 기본적인 while, if 문으로 간단하게 풀 수 있는 방법부터 찬찬히 생각해봐야겠다.

[TIL-240306]

0개의 댓글