友情支持
如果您觉得这个笔记对您有所帮助,看在D瓜哥码这么多字的辛苦上,请友情支持一下,D瓜哥感激不尽,😜
有些打赏的朋友希望可以加个好友,欢迎关注D 瓜哥的微信公众号,这样就可以通过公众号的回复直接给我发信息。
公众号的微信号是: jikerizhi 。因为众所周知的原因,有时图片加载不出来。 如果图片加载不出来可以直接通过搜索微信号来查找我的公众号。 |
518. 零钱兑换 II
给你一个整数数组 coins
表示不同面额的硬币,另给一个整数 `amount`表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0
。
假设每一种面额的硬币有无限个。
题目数据保证结果符合 32 位带符号整数。
示例 1:
输入:amount = 5, coins = [1, 2, 5] 输出:4 解释:有四种方式可以凑成总金额: 5=5 5=2+2+1 5=2+1+1+1 5=1+1+1+1+1
示例 2:
输入:amount = 3, coins = [2] 输出:0 解释:只用面额 2 的硬币不能凑成总金额 3 。
示例 3:
输入:amount = 10, coins = [10] 输出:1
提示:
-
1 <= coins.length <= 300
-
1 <= coins[i] <= 5000
-
coins
中的所有值 互不相同 -
0 <= amount <= 5000
思路分析
一道动态规划,是 322. 零钱兑换 的延伸题目。
假设 dp[i][c]
表示使用前 i
个硬币表示金额为 c
的方案。那么对于当前的硬币 i
,有两个选择:
-
选用:\(dp[i][c] = dp[i][c - coin[i]]\)。注意:由于硬币可以重复使用,即使选用,也要从
i
开始向前递推。 -
不选:\(dp[i][c] = dp[i-1][c]\)。不选,则从
i - 0
开始向前递推。
那么,根据加法原理, \(dp[i][c] = dp[i-1][c] + dp[i][c - coin[i]]\)
注意:不同嵌套顺序表示不同意义。
先金额后硬币,会导致重复计数:

先硬币再金额,就可以避免重复计数的问题:

-
一刷
-
一刷(优化)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* @author D瓜哥 · https://www.diguage.com
* @since 2025-10-10 16:56:01
*/
public int change(int amount, int[] coins) {
int[][] dp = new int[coins.length + 1][amount + 1];
dp[0][0] = 1;
for (int i = 0; i < coins.length; i++) {
for (int j = 0; j <= amount; j++) {
if (coins[i] > j) {
dp[i + 1][j] = dp[i][j];
} else {
dp[i + 1][j] = dp[i][j] + dp[i + 1][j - coins[i]];
}
}
}
return dp[coins.length][amount];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* @author D瓜哥 · https://www.diguage.com
* @since 2025-10-10 09:41:28
*/
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
}