什么是完全背包,就是在01背包的基础上每个物品可以放无数次,在代码中和01背包不一样的地方只有在遍历顺序上不一致,在遍历背包的顺序上 01背包是从后往前遍历,在完全背包中是从前往后遍历。
第一题:
原题链接:518. 零钱兑换 II - 力扣(LeetCode)
思路:
这是一道十分经典的完全背包问题,
首先确认dp数组的含义,dp[j]表示总金额为j有dp[j]种方式能够凑成。
dp[0]必须初始化为1;
遍历顺序先遍历物品再遍历背包。这种遍历顺序得到的是组合的问题。
如果是先遍历背包再遍历物品的话就是排列的问题。
代码如下:
class Solution {
public:int change(int amount, vector<int>& coins) {if(coins.size() == 0 ) return 0;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];}
};
第二题:
原题链接:377. 组合总和 Ⅳ - 力扣(LeetCode)
思路:
本题也是完全背包的经典问题,
区别与上一道题就是遍历顺序的不同,要先遍历背包再遍历物品。
其中还需要在写递推公式之前还需要进行判断,因为可能会造成数组越界的问题,首先j - nums[i]必须是大于等于0的,同时在测试用例有两个数组相加之后超过了int的数据,所以需要判断dp[j] < INT_MAX - dp[j - num[i]].
class Solution {
public:int combinationSum4(vector<int>& nums, int target) {if(nums.size() == 0) return 0;vector<int> 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] >= 0 && dp[j] < INT_MAX - dp[j - nums[i]]){dp[j] += dp[j - nums[i]];} }}return dp[target];}
};
第三题:
爬楼梯(进阶版)
之前的爬楼梯只能至多爬两个台阶,
这次进阶版的改为一步一个台阶,两个台阶,三个台阶,...直到m个台阶。问有多少种不同的方法可以爬到楼顶。
这里把1阶, 2阶, ... m阶看成是物品,然后把楼顶看成是背包。
那么问题就转换成了跳到楼顶有几种方法。和上面的解法就一样了!