61
61
62
62
## 解法
63
63
64
- ### 方法一
64
+ ### 方法一:动态规划(完全背包)
65
+
66
+ 我们定义 $f[ i] [ j ] $ 表示使用前 $i$ 种硬币,凑出金额 $j$ 的硬币组合数。初始时 $f[ 0] [ 0 ] = 1$,其余位置的值均为 $0$。
67
+
68
+ 我们可以枚举使用的最后一枚硬币的数量 $k$,那么有式子一:
69
+
70
+ $$
71
+ f[i][j] = f[i - 1][j] + f[i - 1][j - x] + f[i - 1][j - 2 \times x] + \cdots + f[i - 1][j - k \times x]
72
+ $$
73
+
74
+ 其中 $x$ 表示第 $i$ 种硬币的面值。
75
+
76
+ 不妨令 $j = j - x$,那么有式子二:
77
+
78
+ $$
79
+ f[i][j - x] = f[i - 1][j - x] + f[i - 1][j - 2 \times x] + \cdots + f[i - 1][j - k \times x]
80
+ $$
81
+
82
+ 将式子二代入式子一,得到:
83
+
84
+ $$
85
+ f[i][j] = f[i - 1][j] + f[i][j - x]
86
+ $$
87
+
88
+ 最终的答案为 $f[ m] [ n ] $,其中 $m$ 和 $n$ 分别表示硬币的种类数和总金额。
89
+
90
+ 时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别为硬币的种类数和总金额。
65
91
66
92
<!-- tabs:start -->
67
93
68
94
``` python
69
95
class Solution :
70
96
def change (self , amount : int , coins : List[int ]) -> int :
71
- dp = [0 ] * (amount + 1 )
72
- dp[0 ] = 1
73
- for coin in coins:
74
- for j in range (coin, amount + 1 ):
75
- dp[j] += dp[j - coin]
76
- return dp[- 1 ]
97
+ m, n = len (coins), amount
98
+ f = [[0 ] * (n + 1 ) for _ in range (m + 1 )]
99
+ f[0 ][0 ] = 1
100
+ for i, x in enumerate (coins, 1 ):
101
+ for j in range (n + 1 ):
102
+ f[i][j] = f[i - 1 ][j]
103
+ if j >= x:
104
+ f[i][j] += f[i][j - x]
105
+ return f[m][n]
77
106
```
78
107
79
108
``` java
80
109
class Solution {
81
110
public int change (int amount , int [] coins ) {
82
- int m = coins. length;
83
- int [][] dp = new int [m + 1 ][amount + 1 ];
84
- dp [0 ][0 ] = 1 ;
111
+ int m = coins. length, n = amount ;
112
+ int [][] f = new int [m + 1 ][n + 1 ];
113
+ f [0 ][0 ] = 1 ;
85
114
for (int i = 1 ; i <= m; ++ i) {
86
- for (int j = 0 ; j <= amount; ++ j) {
87
- for (int k = 0 ; k * coins[i - 1 ] <= j; ++ k) {
88
- dp[i][j] += dp[i - 1 ][j - coins[i - 1 ] * k];
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 - coins[i - 1 ]];
89
119
}
90
120
}
91
121
}
92
- return dp [m][amount ];
122
+ return f [m][n ];
93
123
}
94
124
}
95
125
```
@@ -98,89 +128,136 @@ class Solution {
98
128
class Solution {
99
129
public:
100
130
int change(int amount, vector<int >& coins) {
101
- vector<int > dp(amount + 1);
102
- dp[ 0] = 1;
103
- for (auto coin : coins) {
104
- for (int j = coin; j <= amount; ++j) {
105
- dp[ j] += dp[ j - coin] ;
131
+ int m = coins.size(), n = amount;
132
+ int f[ m + 1] [ n + 1 ] ;
133
+ memset(f, 0, sizeof(f));
134
+ f[ 0] [ 0 ] = 1;
135
+ for (int i = 1; i <= m; ++i) {
136
+ for (int j = 0; j <= n; ++j) {
137
+ f[ i] [ j ] = f[ i - 1] [ j ] ;
138
+ if (j >= coins[ i - 1] ) {
139
+ f[ i] [ j ] += f[ i] [ j - coins[ i - 1]] ;
140
+ }
106
141
}
107
142
}
108
- return dp [ amount ] ;
143
+ return f [ m ] [ n ] ;
109
144
}
110
145
};
111
146
```
112
147
113
148
```go
114
149
func change(amount int, coins []int) int {
115
- dp := make([]int, amount+1)
116
- dp[0] = 1
117
- for _, coin := range coins {
118
- for j := coin; j <= amount; j++ {
119
- dp[j] += dp[j-coin]
150
+ m, n := len(coins), amount
151
+ f := make([][]int, m+1)
152
+ for i := range f {
153
+ f[i] = make([]int, n+1)
154
+ }
155
+ f[0][0] = 1
156
+ for i := 1; i <= m; i++ {
157
+ for j := 0; j <= n; j++ {
158
+ f[i][j] = f[i-1][j]
159
+ if j >= coins[i-1] {
160
+ f[i][j] += f[i][j-coins[i-1]]
161
+ }
120
162
}
121
163
}
122
- return dp[amount ]
164
+ return f[m][n ]
123
165
}
124
166
```
125
167
126
168
``` ts
127
169
function change(amount : number , coins : number []): number {
128
- let dp = new Array (amount + 1 ).fill (0 );
129
- dp [0 ] = 1 ;
130
- for (let coin of coins ) {
131
- for (let i = coin ; i <= amount ; ++ i ) {
132
- dp [i ] += dp [i - coin ];
170
+ const [m, n] = [coins .length , amount ];
171
+ const f: number [][] = Array .from ({ length: m + 1 }, () => Array (n + 1 ).fill (0 ));
172
+ f [0 ][0 ] = 1 ;
173
+ for (let i = 1 ; i <= m ; ++ i ) {
174
+ for (let j = 0 ; j <= n ; ++ j ) {
175
+ f [i ][j ] = f [i - 1 ][j ];
176
+ if (j >= coins [i - 1 ]) {
177
+ f [i ][j ] += f [i ][j - coins [i - 1 ]];
178
+ }
133
179
}
134
180
}
135
- return dp . pop () ;
181
+ return f [ m ][ n ] ;
136
182
}
137
183
```
138
184
139
185
<!-- tabs: end -->
140
186
141
- ### 方法二
187
+ 我们注意到 $f [ i ] [ j ] $ 只与 $f [ i - 1 ] [ j ] $ 和 $f [ i ] [ j - x ] $ 有关,因此我们可以将二维数组优化为一维数组,空间复杂度降为 $O(n)$。
142
188
143
189
<!-- tabs: start -->
144
190
191
+ ``` python
192
+ class Solution :
193
+ def change (self , amount : int , coins : List[int ]) -> int :
194
+ n = amount
195
+ f = [1 ] + [0 ] * n
196
+ for x in coins:
197
+ for j in range (x, n + 1 ):
198
+ f[j] += f[j - x]
199
+ return f[n]
200
+ ```
201
+
145
202
``` java
146
203
class Solution {
147
204
public int change (int amount , int [] coins ) {
148
- int m = coins. length;
149
- int [][] dp = new int [m + 1 ][amount + 1 ];
150
- dp[0 ][0 ] = 1 ;
151
- for (int i = 1 ; i <= m; ++ i) {
152
- int v = coins[i - 1 ];
153
- for (int j = 0 ; j <= amount; ++ j) {
154
- dp[i][j] = dp[i - 1 ][j];
155
- if (j >= v) {
156
- dp[i][j] += dp[i][j - v];
157
- }
205
+ int n = amount;
206
+ int [] f = new int [n + 1 ];
207
+ f[0 ] = 1 ;
208
+ for (int x : coins) {
209
+ for (int j = x; j <= n; ++ j) {
210
+ f[j] += f[j - x];
158
211
}
159
212
}
160
- return dp[m][amount ];
213
+ return f[n ];
161
214
}
162
215
}
163
216
```
164
217
165
- <!-- tabs: end -->
166
-
167
- ### 方法三
168
-
169
- <!-- tabs: start -->
170
-
171
- ``` java
218
+ ``` cpp
172
219
class Solution {
173
- public int change (int amount , int [] coins ) {
174
- int [] dp = new int [amount + 1 ];
175
- dp[0 ] = 1 ;
176
- for (int coin : coins) {
177
- // 顺序遍历,0-1背包问题是倒序遍历
178
- for (int j = coin; j <= amount; j++ ) {
179
- dp[j] += dp[j - coin];
220
+ public:
221
+ int change(int amount, vector<int >& coins) {
222
+ int n = amount;
223
+ int f[ n + 1] ;
224
+ memset(f, 0, sizeof(f));
225
+ f[ 0] = 1;
226
+ for (int x : coins) {
227
+ for (int j = x; j <= n; ++j) {
228
+ f[ j] += f[ j - x] ;
180
229
}
181
230
}
182
- return dp[amount];
231
+ return f[ n] ;
232
+ }
233
+ };
234
+ ```
235
+
236
+ ```go
237
+ func change(amount int, coins []int) int {
238
+ n := amount
239
+ f := make([]int, n+1)
240
+ f[0] = 1
241
+ for _, x := range coins {
242
+ for j := x; j <= n; j++ {
243
+ f[j] += f[j-x]
244
+ }
245
+ }
246
+ return f[n]
247
+ }
248
+ ```
249
+
250
+ ``` ts
251
+ function change(amount : number , coins : number []): number {
252
+ const n = amount ;
253
+ const f: number [] = Array (n + 1 ).fill (0 );
254
+ f [0 ] = 1 ;
255
+ for (const x of coins ) {
256
+ for (let j = x ; j <= n ; ++ j ) {
257
+ f [j ] += f [j - x ];
258
+ }
183
259
}
260
+ return f [n ];
184
261
}
185
262
```
186
263
0 commit comments