描述
给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。
示例 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
注意:
你可以假设:
0 <= amount (总金额) <= 5000
1 <= coin (硬币面额) <= 5000
硬币种类不超过 500 种
结果符合 32 位符号整数
思路
动态规划的背包问题共有三种:0-1背包、完全背包、子集背包。这道题是其中的完全背包问题的一种变形,完全背包即“有n种物品,每种物品的可以取无限次,求在背包中能装的最大价值是多少?”不过这里求的是装满背包有多少种方案。还是用完全背包问题的方法,枚举在只考虑前i种物品的情况下,凑出金额j的每一种情况。
按照背包问题的套路,还是需要使用二维数组dp[i][j]。它代表的含义就是在只考虑前i种物品的情况下,装满容量为j的背包有多少种方案。
初始值:当只考虑前0种硬币时,凑不出任何金额j,即dp[0][*] = 0,要凑出金额为0,那么就只有一种方案,即什么都不选,即dp[*][0] = 1。
状态转移方程:背包容量j=总金额j;硬币面值等于物品价值;这里物品不限量。
当背包容量不能装下第i种物品时,则dp[i][j] = dp[i-1][j],即不装入第i种物品,则和只考虑前i-1种物品是一样的。
当背包容量能装下第i种物品时,则dp[i][j] = dp[i-1][j] + dp[i][]j-coins[i-1],因为coins是从0开始索引的,所以是i-1。既然能装下第i种物品,那么这时的凑出背包容量j的方案总数就应该等于使用第i种物品和不使用第j种物品的方案之和。若不使用第i种硬币,那便是使用前i-1种硬币凑出j的方案数dp[i-1][j];若使用第i种硬币,则在减去第i种硬币面值的情况下,剩余的面值的方案数再加上第i种硬币的面值即可凑出总金额j。这里为什么是dp[i][j - coins[i-1]]呢,因为第i种硬币是无限的,前面的总金额为j - coins[i-1]的情况下可能已经使用了第i种硬币。
解答
class Solution {
public:
int change(int amount, vector<int>& coins) {
int size = coins.size();
vector<vector<int> > dp(size + 1, vector<int>(amount + 1, 0));
for(int i = 0;i <= size; ++ i) dp[i][0] = 1;
for(int i = 1;i <= size; ++i)
for(int j=1; j <= amount;++ j){
if(j >= coins[i-1])//能装下
dp[i][j] = dp[i-1][j] + dp[i][j-coins[i-1]];//不装+装入
else//装不下
dp[i][j] = dp[i-1][j];
}
return dp[size][amount];
}
};
硬币组合计数
本文介绍了一种利用动态规划解决完全背包问题的算法——计算给定面额的硬币能够凑成特定总金额的不同组合数量。通过具体示例展示了如何初始化二维数组dp,并给出状态转移方程。
1826

被折叠的 条评论
为什么被折叠?



