LeetCode 518 零钱兑换 II
题目链接:https://leetcode.cn/problems/coin-change-ii/
思路:
dp数组的含义
dp[j]代表金额为j时有多少种方法
递推公式
本题相当于求装满容量为j的背包有几种方法。是一个组合问题。即[1,2]和[2,1]是同一种方法。
初始化
为了可以满足递推公式,dp[0]=1,其余初始化为0即可(因为防止影响后面的累加结果)
遍历顺序
组合问题:先物品后背包
排列问题:先背包后物品
代码:
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int>dp(amount+1,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];
}
};
总结
做法和昨天的目标和差不多,疑惑点在于遍历顺序的不一样为什么代表了不一样的问题。
LeetCode 377 组合总和 Ⅳ
题目链接:https://leetcode.cn/problems/combination-sum-iv/
思路:
dp数组的含义
dp[j]代表target为j时有多少种方法
递推公式
本题相当于求装满容量为j的背包有几种方法。但本题是一个排序问题。题目明确规定不同的排序顺序是不同的组合。
初始化
为了可以满足递推公式,dp[0]=1,其余初始化为0即可(因为防止影响后面的累加结果)
遍历顺序
组合问题:先物品后背包
排列问题:先背包后物品
代码:
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<long long>dp(target+1,0);
dp[0] = 1;
for(int j = 0; j <= target; j++)
{
for(int i = 0; i < nums.size(); i++)
{
if(j >= nums[i] && dp[j] < INT_MAX - dp[j - nums[i]])
dp[j] += dp[j - nums[i]];
}
}
return dp[target];
}
};
总结
要记住不同遍历顺序代表的是什么问题。
今日总结:
纯完全背包类问题——遍历顺序可以相互颠倒
求装满容量为j的背包有多少种方法:
1、如果是组合问题,即元素的顺序不影响方法,[1,2]和[2,1]是同一种方法——零钱兑换II
遍历顺序是先物品后背包
2、如果是排序问题,即元素的顺序影响方法,[1,2]和[2,1]是不同的方法——组合总和IV
遍历顺序是先背包后物品。