完全背包理论基础
完全背包与01背包的区别在于:完全背包同一物品可装多次,而01背包每个物品只能装一次。
因此遍历容量时,从前向后遍历即可!
关于遍历顺序,也与01背包有差别,01背包一维数组只能先遍历物品,而完全背包问题先遍历哪个都可以。
518. 零钱兑换
完全背包解题思路:
每一种面额的硬币有无限个——完全背包问题。
可将问题转换为,从[0,i]中选硬币,每种硬币有无限个,硬币的和为j,共有dp[j]种组合。
初始化dp[0]=1;
因为是求有多少种方法(和一和零题类似),因此
状态转移方程:dp[j]=dp[j]+dp[j-nums[i]];
完全背包问题,从前向后遍历容量。
组合问题,外层遍历物品,内层遍历背包容量。
public int change(int amount, int[] coins) {
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. 组合总和 Ⅳ
本题与上一题的区别在于:本题求排列,上一题求组合。
组合问题:先遍历物品,再遍历容量。
排列问题:先遍历容量,再遍历物品。
本题可转化为:从[0,i]中选数,和为j,共有target[j]种方法。
状态转移方程与上题相同:dp[j]=dp[j]+dp[j-nums[i]];
遍历时记得加上判断条件j-nums[i]>=0,防止下标越界。
public int combinationSum4(int[] nums, int target) {
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]>=0){
dp[j]+=dp[j-nums[i]];
}
}
}
return dp[target];
}