完全背包
要求:有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次) ,求解将哪些物品装入背包里物品价值总和最大。
思路
完全背包和01背包问题唯一不同的地方就是,每种物品有无限件。
01背包内嵌的循环是从大到小遍历,为了保证每个物品仅被添加一次
for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
而完全背包的物品是可以添加多次的,所以要从小到大去遍历
// 先遍历物品,再遍历背包
for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = weight[i]; j <= bagWeight ; j++) { // 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
01背包中二维dp数组的两个for遍历的先后循序是可以颠倒了,一维dp数组的两个for循环先后循序一定是先遍历物品,再遍历背包容量。
在完全背包中,对于一维dp数组来说,其实两个for循环嵌套顺序是无所谓的!
因为dp[j] 是根据 下标j之前所对应的dp[j]计算出来的。 只要保证下标j之前的dp[j]都是经过计算的就可以了。
// 先遍历物品,在遍历背包
function BagProblem(weight, value, size){
let len = weight.length
let dp = Array(size+1).fill(0)
for(let i =0; i<len; i++){ //遍历物品
for(let j=weight[i]; j<=size; j++){ //遍历背包
dp[j] = Math.max(dp[j], dp[j-weight[i]] + value[i])
}
}
return dp[size]
}
// 先遍历背包,再遍历物品
function BagProblem(weight, value, size){
let len = weight.length
let dp = Array(size+1).fill(0)
for(let j=0; j<=size; j++){ //遍历背包
for(let i=0; i<=len; i++){ //遍历物品
if (j >= weight[i]) {
dp[j] = Math.max(dp[j], dp[j-weight[i]] + value[i])
}
}
}
return dp[size]
}
518. 零钱兑换 II
要求:给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。
假设每一种面额的硬币有无限个。
题目数据保证结果符合 32 位带符号整数。
思路
dp[j]:凑成总金额j的货币组合数为dp[j]
递推公式:dp[j] += dp[j - coins[i]]
dp[j] 就是所有的dp[j - coins[i]](考虑coins[i]的情况)相加
dp数组初始化: dp[0] = 1
如果dp[0] = 0 的话,后面所有推导出来的值都是0了。
var change = function(amount, coins) {
let dp = Array(amount+1).fill(0)
dp[0] = 1
for(let i=0; i<coins.length; i++){
for(let j=coins[i]; j<=amount; j++){
dp[j] += dp[j-coins[i]]
}
}
return dp[amount]
};
377. 组合总和 Ⅳ
要求:给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。
题目数据保证答案符合 32 位整数范围。
思路
本题要求的是排列,所以需要注意遍历顺序
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
所以本题外层是背包,内层是物品。
var combinationSum4 = function(nums, target) {
let dp = Array(target+1).fill(0)
dp[0] = 1
for(let j=0; j<=target; j++){
for(let i=0; i<nums.length; i++){
if (j - nums[i] >= 0){
dp[j] += dp[j-nums[i]]
}
}
}
return dp[target]
};