文章目录
- 518.零钱兑换II
- 思路
- 代码实现
- 377. 组合总和 Ⅳ
- 思路
- 代码实现
518.零钱兑换II
题目链接
思路
- 确定dp数组(dp table)以及下标的含义
dp[j]:组合元素和为j的组合方式 - 确定递推公式
题目不是选取最优解,而是求路径总和,则取不同数字的零钱coin[i]时都有dp[j-coin[i]]种方法,
则dp[j]=dp[j-coin[i]] - dp数组如何初始化
后台题目要求是dp[0]=1,这里题目没给出准确的说法 - 确定遍历顺序
外层for循环从前往后,内层for循环也是从前往后
这和01背包完全不同,根本原因就是这里的钱每个面额的数量都没有限制,所以可以重复选取
但外层for循环和内存for循环不可以调换,因为现在是先遍历钱,钱是不会出现{5,1}和{1,5}这样的重复现象的;但如果钱变成内层for循环的话,就可以重复选取,这就是后面那道题的排列问题 - 举例推导dp数组
代码实现
class Solution {
public:int change(int amount, vector<int>& coins) {vector<int> dp(10010,0);dp[0]=1;for(int i=0;i<coins.size();i++){for(int j=coins[i];j<=amount;j++){dp[j]+=dp[j-coins[i]];}}return dp[amount];}
};
377. 组合总和 Ⅳ
题目链接
思路
这道题就是排列问题
- 确定dp数组(dp table)以及下标的含义
dp[j]:组合元素和为j的组合方式 - 确定递推公式
题目不是选取最优解,而是求路径总和,则取不同数字的零钱coin[j]时都有dp[i-coin[j]]种方法,
则dp[i]=dp[i-coin[j]] - dp数组如何初始化
后台题目要求是dp[0]=1,这里题目没给出准确的说法 - 确定遍历顺序
外层for循环从前往后,内层for循环也是从前往后
这就是排列问题,{5,1}和{1,5}都是正确结果。而钱变成内层for循环的话,就可以重复选取。先遍历背包容量,当容量允许装入背包,就可以累加记录方法种类,代码实现和上一道题差不多,只是换了内外层的遍历 - 举例推导dp数组
这里有一个dp[i]<INT_MAX-dp[i-nums[j]]操作,因为测试数据比较大时累加结果可能超过了INT_MAX,为了保证数据不溢出,就需要判断dp[i]+dp[i-nums[j]]<INT_MAX是否成立,而dp[i]+dp[i-nums[j]]可能还是会溢出,所以只能用减法写
代码实现
class Solution {
public:int combinationSum4(vector<int>& nums, int target) {vector<int> dp(10010,0);dp[0]=1;for(int i=0;i<=target;i++){for(int j=0;j<nums.size();j++){if(i>=nums[j]&&dp[i]<INT_MAX-dp[i-nums[j]])dp[i]+=dp[i-nums[j]];}}return dp[target];}
};