518.零钱兑换II
题目链接:518. 零钱兑换 II - 力扣(LeetCode)
解题思路:
这个题目是完全背包的第一个应用题。主要的关注点在于01背包和完全背包的区别把:
1.循环的内外层是否可以交换
二维dp数组的01背包和完全背包都是可以交换内外层循环的,背包容量在外也行,物品在外也行
一维dp数组的01背包不可以交换内外层循环,一定是物品在外,容量在内,因为内层循环需要逆向遍历。
一维dp数组的完全背包问题可以交换内外层循环的顺序,因为内层容量的循环要正向遍历。用到的都是前面的值,前面的值肯定都已经有递推结果了。
2.循环的遍历方向
1维dp数组的01背包内层容量遍历必须是从后向前的
1维dp数组的完全背包内层背包容量遍历必须是从前向后的
但是本题虽然是完全背包的一个应用题,但是并不能交换内外层循环的顺序,因为本题像要求的是有多少种符合要求的组合数,这个结果是不需要考虑元素顺序的。
将物品循环放在外层,求出的结果就是排列的种类总数,而不是组合的种类总数。
class Solution {
public int change(int amount, int[] coins) {
/**
* 该题目不是01背包问题了,因为物品可以无限量的取。所以是完全背包问题
* 1.dp[j] 总结j一共有多少种凑的方案
* 2.dp[j] = Math.max(dp[j], dp[j - coins[i]]);
* 3.dp[0] = 1;
*/
int[] dp = new int[amount + 1];
dp[0] = 1;
for(int i = 0; i < coins.length; i++){
for(int j = coins[i]; j <= amount; j++){
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
}
377.组合总和IV
题目链接:377. 组合总和 Ⅳ - 力扣(LeetCode)
解题思路:
这个题就是完全背包问题中的排列总和问题。
class Solution {
public int combinationSum4(int[] nums, int target) {
/**
* 该题目是完全背包问题中的排列总数问题,直接确定背包容量在外层,物品在内层
* 1.dp[j] 组成j有多少种排列
* 2.dp[j] = dp[j] + dp[j - nums[i]]
* 3.dp[0] = 1;
* 4.内外层正向循环,外层容量 内层物品
*/
int[] dp = new int[target + 1];
dp[0] = 1;
for(int j = 0; j <= target; j++){
for(int i = 0; i < nums.length; i++){
if(j >= nums[i]) dp[j] += dp[j - nums[i]];
}
}
return dp[target];
}
}