518. 零钱兑换 II
1.代码
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int>f(amount + 1, 0);
f[0] = 1;
for (int i = 0; i < coins.size(); i++) {
for (int j = coins[i]; j <= amount; j++) {
f[j] += f[j - coins[i]];
}
}
return f[amount];
}
};
2.动规五部曲
1.确定dp数组和其下标含义
由题目说可知求选择钱票得到总和为target的方案数,dp[j]相当于选择物品体积相加为i的方案数
2.递推公式
每次加入物品,都有可能到达体积j,所以在每次加上这个物品到达j时加上这个方案数
f[j] += f[j - coins[i]];
3.初始化
因为在for循环和dp公式中没有确切的值,肯定需要初始化,初始化第一个就可以保证后面的推导出来了,f[0]=1,代表背包为0时的方案数为1,说明不选任何东西
4.确定遍历顺序
第一层for循环就是选取每个物品,第二层循环也为正序,因为需要重复选取,正序就能用到之前的背包了,所以可以重复选取,第二层就是遍历每一个不同大小的背包来装每一个物品进行筛选。
5.举例说明dp数组
377. 组合总和 Ⅳ
1.代码
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<int>f(target + 1, 0);
f[0] = 1;
for (int i = 0; i <= target; i++) {
for (int j = 0; j < nums.size(); j++) {
if (i >= nums[j] && f[i] < INT_MAX - f[i - nums[j]]) f[i] += f[i - nums[j]];
}
}
return f[target];
}
};
1.动规五部曲
4.确定遍历顺序
因为是求排列数,不是组合数,说明不一样的顺序也可以,如果物品放到里面时,外面的每个背包都可以进行物品筛选,所以两层for循环需要反过来顺序
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
第一层遍历背包,第二层遍历物品,因为顺序翻过来了 ,那么不能在for循环中增加判断条件。在for循环外加if就行了,还需要确保超过int最大范围
5.模拟