重点:
(1)本题的零钱兑换,求的是固定金额的组合个数,即不考虑顺序;
(2)动规能解决组合和排列问题,但循环内外不同;
(3)本题来说:
——外层for循环遍历物品(钱币),内层for循环遍历背包(金钱总额),计算得组合数;
——反之,计算得出的是排列数;
难度中等
给你一个整数数组 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
解析:
(1)确定dp数组及下标含义:dp[i]表示金额为i的组合数;
(2)递推公式:dp[i]=SUM(dp[ i-coins[j] ]
(3)初始化:dp[0]=1,就是不取这一种办法。
(5)举例推导:例如[1, 2, 5],总金额为5。dp[0]=0,dp[1]=SUM(dp0=1),dp[2]=SUM(dp1=1,dp0=1),dp3=SUM(dp1=1, dp2=2,)
代码:
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> dp(amount+1,0);
sort(coins.begin(),coins.end());
dp[0]=1;
for(int j=0;j<coins.size();j++){
for(int i=1;i<=amount;i++)
if(i>=coins[j])
dp[i]+=dp[i-coins[j]];
}
return dp[amount];
}
};