【代码训练营】day44 | 完全背包理论 & 518. 零钱兑换 II & 377. 组合总和 Ⅳ

所用代码 java

完全背包

01背包物品只能使用一次 – 倒序遍历

for(i = 0; i < weight.length; i++){ 物品
    for (j = bagWeight; j >= weight[i]; j--){ 背包
        dp[j] = max(dp[j], dp[j-weight[i]] + value[i])
    }
}

完全背包物品可以使用无限次 – 正序遍历

for(i = 0; i < weight.length; i++){ 物品
    for (j = weight[i]; j <= bagWeight; j++){ 背包
        dp[j] = max(dp[j], dp[j-weight[i]] + value[i])
    }
}

完全背包for循环中可以颠倒,先遍历谁都可以

零钱兑换 II LeetCode 518

题目链接:零钱兑换 II LeetCode 518 - 中等

思路

  • dp[j]:装满背包j的情况有dp[j]种

  • 递推公式:dp[j] += dp[j-coins[i]]

  • 初始化:dp[0] = 1 如果等于0,后面累加就会一直是0, 空集也是一种方法

    • dp[1] += dp[0],1要从0得到结果然后继续累加
  • 遍历方向:coins[i] <= j <= amount

  • 打印dp

class Solution {
    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]];
//                System.out.print("\tdp[j] = " + dp[j]);
            }
//            System.out.println();
        }
        return dp[amount];
    }
}

总结

先遍历物品,后遍历背包,保证了物品是从1、2、3开始的,不会有重复,也就是说这是一个组合数

若先遍历背包,再遍历物品,每次物品都是从1开始,就会有重复数,如1,2 2,1 但是这可以代表排列数

组合总和 Ⅳ leetCode 377

题目链接:组合总和 Ⅳ leetCode 377 - 中等

思路

  • dp[j] :和为j的情况有dp[j]种
  • 递推:dp[j] += dp[j-nums[i]]
  • 初始化:dp[0] = 1
  • 遍历顺序:先背包,后物品
class Solution {
    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]) dp[j] += dp[j-nums[i]];
                System.out.print("\tdp[j] = " +dp[j]);
            }
            System.out.println();
        }
        return dp[target];
    }
}

总结

背包为0可以装下物品 1 2 3 这其实是一个悖论,也可以认为是背包为0的可以装下无限大的东西。但是我认为把这个看成一个初始化无意义的值就行了,以防止出现后序累加的值一直为0。

dp数组的打印值

        dp[j] = 1   dp[j] = 1   dp[j] = 1
        dp[j] = 1   dp[j] = 1   dp[j] = 1
        dp[j] = 1   dp[j] = 2   dp[j] = 2
        dp[j] = 2   dp[j] = 3   dp[j] = 4
        dp[j] = 4   dp[j] = 6   dp[j] = 7

若是觉得这值确实没必要,我们其实可以从j=1开始遍历,所打印的值就有助于对于dp数组的理解。

        dp[j] = 1   dp[j] = 1   dp[j] = 1
        dp[j] = 1   dp[j] = 2   dp[j] = 2
        dp[j] = 2   dp[j] = 3   dp[j] = 4
        dp[j] = 4   dp[j] = 6   dp[j] = 7

所以,通过这两个题,我们可以明白:

  • 先遍历物品,再遍历背包:组合问题 - 无重复
  • 先遍历背包,再遍历物品:排列数 - 有重复(可排序)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值