|
| 1 | + |
| 2 | +//1. top-down |
| 3 | +var coinChange = function(coins, amount) { |
| 4 | + if(amount == 0 ) return 0 |
| 5 | + /* |
| 6 | + 점화식 : dp[n] = Math.min(dp[n],dp[n-k]+1) |
| 7 | + */ |
| 8 | + const dp = new Array(amount+1).fill(Math.pow(10,4)); |
| 9 | + for(let c of coins){ |
| 10 | + dp[c] = 1 |
| 11 | + } |
| 12 | + function dfs(idx,coin){ |
| 13 | + if(idx + coin > amount) return |
| 14 | + dp[idx+coin] = Math.min(dp[idx+coin],dp[idx]+1) |
| 15 | + if(idx + coin == amount){ |
| 16 | + return |
| 17 | + }else{ |
| 18 | + for(let c of coins){ |
| 19 | + dfs(idx+coin,c) |
| 20 | + } |
| 21 | + } |
| 22 | + } |
| 23 | + dfs(0,coins[0]) |
| 24 | + |
| 25 | + if(dp[amount] > amount) return -1 |
| 26 | + |
| 27 | + return dp[amount] |
| 28 | + |
| 29 | +}; |
| 30 | + |
| 31 | +// 타임리밋에 걸린다. dfs의 가지치기가 덜 되어서 그렇다. |
| 32 | +// 그렇다면, 순차적인 dp를 좀더 활용하는 것이 좋아보인다. 현재로서는 메모이제이션의 이점을 제대로 활용할 수 없어보인다. |
| 33 | + |
| 34 | + |
| 35 | + |
| 36 | +//2. bottom-up |
| 37 | +var coinChange = function(coins, amount) { |
| 38 | + coins = coins.filter(x=> x<=amount) |
| 39 | + if(amount == 0) return 0 |
| 40 | + /* |
| 41 | + 점화식 : dp[n] = Math.min(dp[n],dp[n-k]+1) |
| 42 | + */ |
| 43 | + const dp = new Array(amount+1).fill(Math.pow(10,4)+1); |
| 44 | + dp[0] = 0 |
| 45 | + //dfs를 쓰고 싶지 않다면, amount만큼의 for문을 돌면서 dp를 초기화해주면 된다. |
| 46 | + for(let i=1; i <amount+1; i++){ |
| 47 | + for(let coin of coins){ |
| 48 | + if(i-coin >= 0){ |
| 49 | + dp[i] = Math.min(dp[i-coin] + 1,dp[i]) |
| 50 | + } |
| 51 | + } |
| 52 | + } |
| 53 | + if(dp[amount] > amount) return -1 |
| 54 | + return dp[amount] |
| 55 | + |
| 56 | +}; |
| 57 | + |
| 58 | +/** |
| 59 | +dfs를 쓰고 싶지 않다면, amount만큼의 for문을 돌면서 dp를 초기화해주면 된다. |
| 60 | +처음에 coins = coins.filter(x=> x<=amount) |
| 61 | +이렇게 쓴 이유는, amount보다 작은 코인만 필터하여 최적화한다. |
| 62 | +
|
| 63 | +이 문제 풀이 소요시간이 1시간이 넘었는데, |
| 64 | +그 이유가, i-coin이 아니라, i+coin을 기준을 삼았었다. |
| 65 | +그러다보니 그러다 보니 각 금액 `i`의 최솟값을 찾기 위해 `dp[i]`를 `dp[i-coin]` 기반으로 갱신해야 한다는 핵심적인 아이디어를 적용하기 어려웠다. |
| 66 | +`dp[i+coin]` 방식으로 접근하면, `dp[i]` 자체가 아직 최적의 상태가 아닌데도 그 값을 기반으로 미래의 `dp[i+coin]`을 업데이트하려 하기 때문에, 정확한 최적해를 찾아내기 어려웠다. |
| 67 | +현재 금액 `i`를 만들기 위한 가장 효율적인 방법을 과거의 `dp[i-coin]`에서 찾는 '바텀업(Bottom-Up)' 방식이 이 문제에 훨씬 적합하다는 것을 깨닫는 데 시간이 걸렸다. |
| 68 | +
|
| 69 | +
|
| 70 | +
|
| 71 | +시간복잡도: O(n * m) |
| 72 | +공간 복잡도 : O(n) |
| 73 | + */ |
0 commit comments