友情支持
如果您觉得这个笔记对您有所帮助,看在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];
}

