题目
给你一个整数数组 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
题解
同样使用动态规划,定义
d
p
[
j
]
dp[j]
dp[j]表示为在当前硬币选项中得到总金额
j
j
j的方案数。
假设当前遍历的硬币额度为coin,状态转移方程:
d
p
[
j
]
=
{
d
p
[
j
]
,
j
<
c
o
i
n
d
p
[
j
]
+
d
p
[
j
−
c
o
i
n
]
,
j
≥
c
o
i
n
dp[j] = \left \{ \begin{aligned} &dp[j], & j < coin\\ &dp[j]+dp[j-coin], & j \geq coin \end{aligned} \right.
dp[j]={dp[j],dp[j]+dp[j−coin],j<coinj≥coin
因为每增加一种硬币额度coin
(
c
o
i
n
≤
j
≤
a
m
o
u
n
t
)
(coin \leq j \leq amount)
(coin≤j≤amount),则存在一组组合
d
p
[
j
−
c
o
i
n
]
dp[j-coin]
dp[j−coin]加上coin得到amount,因此
d
p
[
j
]
dp[j]
dp[j]的选择包括上一轮的
d
p
[
j
]
dp[j]
dp[j]和添加coin的
d
p
[
j
−
c
o
i
n
]
dp[j-coin]
dp[j−coin]。
class Solution {
public int change(int amount, int[] coins) {
// dp[j]表示在当前硬币可选项中得到amount的组合数量
int len = coins.length;
int[] dp = new int[amount + 1];
dp[0] = 1;
for(int coin : coins){
for(int j = 0; j <= amount; j++){
if(j >= coin){
dp[j] += dp[j - coin];
}
}
}
return dp[amount];
}
}