|
37 | 37 |
|
38 | 38 | **方法一:动态规划**
|
39 | 39 |
|
| 40 | +我们定义 $f[i][j]$ 表示只使用前 $i$ 种硬币的情况下,凑成总金额为 $j$ 的方案数。初始时 $f[0][0]=1$,其余元素都为 $0$。答案为 $f[4][n]$。 |
| 41 | + |
| 42 | +考虑 $f[i][j]$,我们可以枚举使用的第 $i$ 种硬币的个数 $k$,其中 $0 \leq k \leq j / c_i$,那么 $f[i][j]$ 就等于所有 $f[i−1][j−k \times c_i]$ 之和。由于硬币的数量是无限的,因此 $k$ 可以从 $0$ 开始取。即状态转移方程如下: |
| 43 | + |
| 44 | +$$ |
| 45 | +f[i][j] = f[i - 1][j] + f[i - 1][j - c_i] + \cdots + f[i - 1][j - k \times c_i] |
| 46 | +$$ |
| 47 | + |
| 48 | +不妨令 $j = j - c_i$,那么上面的状态转移方程可以写成: |
| 49 | + |
| 50 | +$$ |
| 51 | +f[i][j - c_i] = f[i - 1][j - c_i] + f[i - 1][j - 2 \times c_i] + \cdots + f[i - 1][j - k \times c_i] |
| 52 | +$$ |
| 53 | + |
| 54 | +将二式代入一式,得到: |
| 55 | + |
| 56 | +$$ |
| 57 | +f[i][j]= |
| 58 | +\begin{cases} |
| 59 | +f[i - 1][j] + f[i][j - c_i], & j \geq c_i \\ |
| 60 | +f[i - 1][j], & j < c_i |
| 61 | +\end{cases} |
| 62 | +$$ |
| 63 | + |
| 64 | +最后的答案即为 $f[4][n]$。 |
| 65 | + |
| 66 | +时间复杂度 $O(C \times n)$,空间复杂度 $O(C \times n)$,其中 $C$ 为硬币的种类数。 |
| 67 | + |
| 68 | +我们注意到,$f[i][j]$ 的计算只与 $f[i−1][..]$ 有关,因此我们可以去掉第一维,将空间复杂度优化到 $O(n)$。 |
| 69 | + |
40 | 70 | <!-- tabs:start -->
|
41 | 71 |
|
42 | 72 | ### **Python3**
|
43 | 73 |
|
44 | 74 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
45 | 75 |
|
46 | 76 | ```python
|
| 77 | +class Solution: |
| 78 | + def waysToChange(self, n: int) -> int: |
| 79 | + mod = 10**9 + 7 |
| 80 | + coins = [25, 10, 5, 1] |
| 81 | + f = [[0] * (n + 1) for _ in range(5)] |
| 82 | + f[0][0] = 1 |
| 83 | + for i, c in enumerate(coins, 1): |
| 84 | + for j in range(n + 1): |
| 85 | + f[i][j] = f[i - 1][j] |
| 86 | + if j >= c: |
| 87 | + f[i][j] = (f[i][j] + f[i][j - c]) % mod |
| 88 | + return f[-1][n] |
| 89 | +``` |
47 | 90 |
|
| 91 | +```python |
| 92 | +class Solution: |
| 93 | + def waysToChange(self, n: int) -> int: |
| 94 | + mod = 10**9 + 7 |
| 95 | + coins = [25, 10, 5, 1] |
| 96 | + f = [1] + [0] * n |
| 97 | + for c in coins: |
| 98 | + for j in range(c, n + 1): |
| 99 | + f[j] = (f[j] + f[j - c]) % mod |
| 100 | + return f[n] |
48 | 101 | ```
|
49 | 102 |
|
50 | 103 | ### **Java**
|
51 | 104 |
|
52 | 105 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
53 | 106 |
|
54 | 107 | ```java
|
| 108 | +class Solution { |
| 109 | + public int waysToChange(int n) { |
| 110 | + final int mod = (int) 1e9 + 7; |
| 111 | + int[] coins = {25, 10, 5, 1}; |
| 112 | + int[][] f = new int[5][n + 1]; |
| 113 | + f[0][0] = 1; |
| 114 | + for (int i = 1; i <= 4; ++i) { |
| 115 | + for (int j = 0; j <= n; ++j) { |
| 116 | + f[i][j] = f[i - 1][j]; |
| 117 | + if (j >= coins[i - 1]) { |
| 118 | + f[i][j] = (f[i][j] + f[i][j - coins[i - 1]]) % mod; |
| 119 | + } |
| 120 | + } |
| 121 | + } |
| 122 | + return f[4][n]; |
| 123 | + } |
| 124 | +} |
| 125 | +``` |
55 | 126 |
|
| 127 | +```java |
| 128 | +class Solution { |
| 129 | + public int waysToChange(int n) { |
| 130 | + final int mod = (int) 1e9 + 7; |
| 131 | + int[] coins = {25, 10, 5, 1}; |
| 132 | + int[] f = new int[n + 1]; |
| 133 | + f[0] = 1; |
| 134 | + for (int c : coins) { |
| 135 | + for (int j = c; j <= n; ++j) { |
| 136 | + f[j] = (f[j] + f[j - c]) % mod; |
| 137 | + } |
| 138 | + } |
| 139 | + return f[n]; |
| 140 | + } |
| 141 | +} |
| 142 | +``` |
| 143 | + |
| 144 | +### **C++** |
| 145 | + |
| 146 | +```cpp |
| 147 | +class Solution { |
| 148 | +public: |
| 149 | + int waysToChange(int n) { |
| 150 | + const int mod = 1e9 + 7; |
| 151 | + vector<int> coins = {25, 10, 5, 1}; |
| 152 | + int f[5][n + 1]; |
| 153 | + memset(f, 0, sizeof(f)); |
| 154 | + f[0][0] = 1; |
| 155 | + for (int i = 1; i <= 4; ++i) { |
| 156 | + for (int j = 0; j <= n; ++j) { |
| 157 | + f[i][j] = f[i - 1][j]; |
| 158 | + if (j >= coins[i - 1]) { |
| 159 | + f[i][j] = (f[i][j] + f[i][j - coins[i - 1]]) % mod; |
| 160 | + } |
| 161 | + } |
| 162 | + } |
| 163 | + return f[4][n]; |
| 164 | + } |
| 165 | +}; |
| 166 | +``` |
| 167 | +
|
| 168 | +```cpp |
| 169 | +class Solution { |
| 170 | +public: |
| 171 | + int waysToChange(int n) { |
| 172 | + const int mod = 1e9 + 7; |
| 173 | + vector<int> coins = {25, 10, 5, 1}; |
| 174 | + int f[n + 1]; |
| 175 | + memset(f, 0, sizeof(f)); |
| 176 | + f[0] = 1; |
| 177 | + for (int c : coins) { |
| 178 | + for (int j = c; j <= n; ++j) { |
| 179 | + f[j] = (f[j] + f[j - c]) % mod; |
| 180 | + } |
| 181 | + } |
| 182 | + return f[n]; |
| 183 | + } |
| 184 | +}; |
| 185 | +``` |
| 186 | + |
| 187 | +### **Go** |
| 188 | + |
| 189 | +```go |
| 190 | +func waysToChange(n int) int { |
| 191 | + const mod int = 1e9 + 7 |
| 192 | + coins := []int{25, 10, 5, 1} |
| 193 | + f := make([][]int, 5) |
| 194 | + for i := range f { |
| 195 | + f[i] = make([]int, n+1) |
| 196 | + } |
| 197 | + f[0][0] = 1 |
| 198 | + for i := 1; i <= 4; i++ { |
| 199 | + for j := 0; j <= n; j++ { |
| 200 | + f[i][j] = f[i-1][j] |
| 201 | + if j >= coins[i-1] { |
| 202 | + f[i][j] = (f[i][j] + f[i][j-coins[i-1]]) % mod |
| 203 | + } |
| 204 | + } |
| 205 | + } |
| 206 | + return f[4][n] |
| 207 | +} |
| 208 | +``` |
| 209 | + |
| 210 | +```go |
| 211 | +func waysToChange(n int) int { |
| 212 | + const mod int = 1e9 + 7 |
| 213 | + coins := []int{25, 10, 5, 1} |
| 214 | + f := make([]int, n+1) |
| 215 | + f[0] = 1 |
| 216 | + for _, c := range coins { |
| 217 | + for j := c; j <= n; j++ { |
| 218 | + f[j] = (f[j] + f[j-c]) % mod |
| 219 | + } |
| 220 | + } |
| 221 | + return f[n] |
| 222 | +} |
56 | 223 | ```
|
57 | 224 |
|
58 | 225 | ### **TypeScript**
|
59 | 226 |
|
60 | 227 | ```ts
|
61 | 228 | function waysToChange(n: number): number {
|
62 |
| - const MOD = 10 ** 9 + 7; |
63 |
| - let coins = [1, 5, 10, 25]; |
64 |
| - let dp = new Array(n + 1).fill(0); |
65 |
| - dp[0] = 1; |
66 |
| - for (let coin of coins) { |
67 |
| - for (let i = coin; i <= n; ++i) { |
68 |
| - dp[i] += dp[i - coin]; |
| 229 | + const mod = 10 ** 9 + 7; |
| 230 | + const coins: number[] = [25, 10, 5, 1]; |
| 231 | + const f: number[][] = Array(5) |
| 232 | + .fill(0) |
| 233 | + .map(() => Array(n + 1).fill(0)); |
| 234 | + f[0][0] = 1; |
| 235 | + for (let i = 1; i <= 4; ++i) { |
| 236 | + for (let j = 0; j <= n; ++j) { |
| 237 | + f[i][j] = f[i - 1][j]; |
| 238 | + if (j >= coins[i - 1]) { |
| 239 | + f[i][j] = (f[i][j] + f[i][j - coins[i - 1]]) % mod; |
| 240 | + } |
| 241 | + } |
| 242 | + } |
| 243 | + return f[4][n]; |
| 244 | +} |
| 245 | +``` |
| 246 | + |
| 247 | +```ts |
| 248 | +function waysToChange(n: number): number { |
| 249 | + const mod = 10 ** 9 + 7; |
| 250 | + const coins: number[] = [25, 10, 5, 1]; |
| 251 | + const f: number[] = new Array(n + 1).fill(0); |
| 252 | + f[0] = 1; |
| 253 | + for (const c of coins) { |
| 254 | + for (let i = c; i <= n; ++i) { |
| 255 | + f[i] = (f[i] + f[i - c]) % mod; |
69 | 256 | }
|
70 | 257 | }
|
71 |
| - return dp.pop() % MOD; |
| 258 | + return f[n]; |
72 | 259 | }
|
73 | 260 | ```
|
74 | 261 |
|
|
0 commit comments