골드 레벨 문제를 풀다가 어려워지면 바로 실버 문제로 리프레시를 해보자. 하하...언젠간 골드 레벨 문제도 바로바로 풀 수 있게될거야!
나는 이 문제를 재귀로 접근하는 풀이법을 직관적으로 떠올렸다.
만약 n이라는 금액을 만들기위해 5짜리 동전을 하나 사용하는 경우, n-5라는 금액을 만들기 위해서 필요한 최소한의 동전 개수를 구하고, n-5라는 금액을 만들기 위해 5짜리 동전을 하나 사용하는 경우, n-5-5라는 금액을 만들기 위해서 필요한 최소한의 동전 개수를 구하고...
이렇게 말이다.
하지만, 이 재귀 풀이의 경우에 발생할 문제점이 한 가지 있다.
중복되는 계산이 많다는 것!
f(n)을 이제부터 n금액을 만들기 위한 최소한의 동전 개수를 구하는 함수라 부르겠다.
금액 15를 만들기 위해 5짜리 동전 하나를 사용하는 경우, f(15) = 1+ f(10)이다.
금액 12를 만들기 위해 2짜리 동전 하나를 사용하는 경우, f(12) = 1 + f(10)이다.
그렇다면 금액 17을 만드는 경우를 생각해보자. f(10)의 계산이 불필요하게 중복이 될 것이다.
왜 dp냐고? 재귀는 dp와 조건이 같다.
DP로 접근할 때는, dp 테이블의 인덱스가 의미하는 값
과, 해당 인덱스 위치에 저장되는 값의 의미
를 마음 속으로 정의해놓고 로직을 생각해야 수월하다. 내가 어떤 데이터를 메모이제이션 해야하지?
를 잘 생각해보자.
금액 k를 만들기 위한 최소한의 동전 개수
그렇다. 그러면 dp 테이블의 초기값은 어떠해야 하는가? 아마 매우 큰 수
여야 할 것이다. 그래야 최소값을 업데이트하기 수월하니까 말이다.
그래서 dp테이블을 최대 정수
로 초기화해주었다. 더불어 dp[0]을 0으로 초기화해주었는데, 그 이유는 동전 하나로 한 번에 어떤 금액을 만들 수 있는 경우를 처리하기 위해서이다.
이후 과정은 쉽다.
dp테이블의 인덱스는 내가 만들고자 하는 금액으로 삼고,
여기까지 생각을 했다면 로직을 작성해보자.
내 예시코드가 없어도 아마 문제를 거뜬히 맞출 수 있을 것이다.
다만, 문제 마지막에 금액을 주어진 동전으로 만들 수 없는 경우, -1을 출력하는 조건에 주의하자! (그렇지 않으면 95%정도에서 틀리게 된다 ㅜㅜ)
아아... 방랑자여, 아쉽지만 정답에 도달하지 못했는가? 그러면 내 변변찮은 예시 코드를 보고 다시 한 번 도전해보시게나.
const N =
require('fs')
.readFileSync(process.platform === 'linux' ? 'dev/stdin' : 'test/test.txt')
.toString()
.trim() * 1
const dp = Array.from({ length: N + 1 }, () => Number.MAX_SAFE_INTEGER)
dp[0] = 0
for (let target = 1; target <= N; target++) {
[2, 5].forEach((coin) => {
if (coin > target) return
dp[target] = Math.min(dp[target], dp[target - coin] + 1)
})
}
console.log(dp[N] > N ? -1 : dp[N])
그럼 화이팅이다!
목차가 벌써 25개.... 좋은 밤 되세요👍