0
点赞
收藏
分享

微信扫一扫

【dp】排列问题——零钱兑换和组合总和IV


文章目录

  • ​​零钱兑换​​
  • ​​组合总和IV​​

零钱兑换

【dp】排列问题——零钱兑换和组合总和IV_动态规划

很明显,本题使用完全背包算法,求解的是组合数,直接使用完全背包算法即可,为什么是组合数呢?

如果题目说 amount=5,coins=[1,2,5] 有9种方法,那就是排列数(挑选的元素有先后顺序),如下:

5=5
5=1+2+2
5=2+1+2
5=2+2+1
5=2+1+1+1
5=1+2+1+1
5=1+1+2+1
5=1+1+1+2
5=1+1+1+1+1

class Solution {
public:
int change(int amount, vector<int>& coins) {
int m = coins.size();
int n = amount;
vector<int> dp(n + 1, 0); // dp[i]:容量为i的背包装满,最多有dp[i]种装法
dp[0] = 1;
// 组合:先物品、后容量
// 遍历物品
for(int i = 0; i < m; i++){
// 完全背包:顺序遍历容量
for(int j = coins[i]; j <= n; j++){
dp[j] = dp[j] + dp[j - coins[i]];
}
}
return dp[n];
}
};

组合总和IV

【dp】排列问题——零钱兑换和组合总和IV_完全背包_02

题目有强调:顺序不同的序列被视作不同的组合

即我们本题求解是排列数

dp[i]: 使用数组nums,凑成整数 i 的排列个数

dp[i] = dp[i-nums[0]] + dp[i-nums[1]] + dp[i-nums[2]] + …

举个例子比如nums = [1,2,3],target = 4

dp[4] = dp[4-1] + dp[4-2] + dp[4-3] = dp[3] + dp[2] + dp[1]

其实就是说4的排列数可以由三部分组成:1和dp[3]、2和dp[2]、3和dp[1]

class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
// 完全背包
// 排列:先容量、后物品
int m = nums.size();
int n = target;
vector<int> dp(n + 1, 0);
dp[0] = 1;
for(int j = 1; j <= n; j++){
for(int i = 0; i < m; i++){
// 每一个小于当前容量j的物品nums[i],都会被当作第一个元素
if(nums[i] <= j) dp[j] += dp[j - nums[i]];
}
}
return dp[n];
}
};

为什么不能先遍历物品,后遍历容量呢?

如果先遍历物品,后遍历容量的话,举一个例子:计算dp[3]的时候,结果集只有 {1,2} 这样的集合,不会有{2,1}这样的集合,因为nums遍历放在外层,3只能出现在1后面!


举报

相关推荐

0 条评论