代码随想录算法训练营第四十四天 | 完全背包 518. 零钱兑换 II 377. 组合总和 Ⅳ

完全背包问题

有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次)
,求解将哪些物品装入背包里物品价值总和最大。

完全背包和01背包问题唯一不同的地方就是,每种物品有无限件

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]);

    }
}

在完全背包中对于一维dp数组来说,其实两个for循环嵌套顺序是无所谓的

//先遍历物品再遍历背包
private 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]);
        }
    }

}

518. 零钱兑换 II

给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。

请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0

假设每一种面额的硬币有无限个。

题目数据保证结果符合 32 位带符号整数。

输入:amount = 5, coins = [1, 2, 5]
输出:4
解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
  1. 确定dp及其下标含义

dp[j]表示金额为j,凑成货币的组合有dp[j]种

  1. 确定递推公式

每个dp[j]都可由dp[j-coins[i]]所确定

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

  1. dp数组初始化

累加的需要将dp[0]=1不然就会后面都为0

  1. 确定遍历顺序

外层是钱币循环,内层可以遍历金钱总额

  1. 举例推导dp数组

amount=5,coins=[1,2,5]

当i=0,conis[0]=1时 [1 1 1 1 1 1]

当i=1,conis[1]=2时 [1 1 2 2 3 3]

当i=2,conis[2]=5时 [1 1 2 2 3 4]

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]];
            }
        }
        return dp[amount];

    }
}

377.组合总和IV

给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。

题目数据保证答案符合 32 位整数范围。

输入:nums = [1,2,3], target = 4
输出:7
解释:
所有可能的组合为:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
请注意,顺序不同的序列被视作不同的组合。
  1. 确定dp数组及其下标含义

dp[i]凑成目标正整数为i的排列个数为dp[i]

  1. 确定递推公式

dp[i] += dp[i - nums[j]];

  1. dp数组初始化

dp[0]=1

  1. 确定遍历顺序

外层for循环遍历背包,内层循环遍历物品

  1. 举例推导dp数组
class Solution {
    public int combinationSum4(int[] nums, int target) {
        int[] dp = new int[target + 1];
        dp[0] = 1;
        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];
    }
}

你可能感兴趣的:(算法,数据结构,动态规划)