代码随想录训练营day44, 完全背包问题, 零钱兑换II, 组合总和IV

完全背包问题

和01背包的区别就是, 物品可以使用无限次, 所以只需要把for循环全部改成正序就行了

private static void testCompletePack(){
    int[] weight = {1, 3, 4};
    int[] value = {15, 20, 30};
    int bagWeight = 4;
    int[] dp = new int[bagWeight + 1];
    for (int i = 0; i < weight.length; i++){ // 遍历物品
        for (int j = weight[i]; j <= bagWeight; j++){ // 遍历背包容量
            dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
        }
    }
    for (int maxValue : dp){
        System.out.println(maxValue + "   ");
    }
}

零钱兑换II

这一题问的是凑成总金额的个数, 也就是在问组合数(无重复)

  1. dp数组含义, 凑成总金额的j的货币组合数为dp[j]
  2. 递推公式: dp[j] += dp[j - coins[i]];
  3. 初始化: dp[0] = 1, 相当于凑成0的方式默认有一种
  4. 遍历顺序: 注意
    1. 如果先遍历物品, 再背包, 那么就不会有重复, 是组合数(比如{1,5})
    2. 如果先背包, 再物品, 那么就是排列数
class Solution {
    public int change(int amount, int[] coins) {
        int[] dp = new int[amount + 1];
        //初始化
        dp[0] = 1;
        //开始递推, 这你问的是combination
        //这里从0开始, 因为初始化的是j; 
        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];
    }
}

组合总和IV

根据题意可以看出, 这道题其实是在求排列

  1. 这道题前面和上一个是一模一样的
  2. 唯一的区别就是for循环的遍历顺序不同, 之前已经分析过

(注意两个细节: i和j的顺序没有变, 但是他们的含义已经变了; 这里为了防止背包比物品小, 要在递推公式前写一个if判断)

class Solution {
    public int combinationSum4(int[] nums, int target) {
        int[] dp = new int[target + 1];
        dp[0] = 1;
        //直接进入递推, 换个遍历顺序就行了
        //这里i, j的含义遍历, 先背包再物品
        for(int i = 0; i <= target; i++){
            for(int j = 0; j < nums.length; j++){
                //这里需要判断一下, 背包比物品大
                if(i >= nums[j]) {
                    dp[i] += dp[i - nums[j]];
                }
            }
        }
        return dp[target];
    }
}

你可能感兴趣的:(算法,动态规划,贪心算法)