随想录Day44 | 完全背包、518. 零钱兑换 II 、377. 组合总和 Ⅳ | 动态规划

85 阅读2分钟

完全背包

思路:

和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循环嵌套顺序同样无所谓!

518. 零钱兑换 II

题目链接:518. 零钱兑换 II

思路:
这题求的是组合总数。

动规五部曲 

1.确定dp数组以及下标的含义

dp[j]的定义为:凑成总金额j的货币组合数为dp[j]

2.确定递推公式

求装满背包有几种方法,一般公式都是:dp[j] += dp[j - nums[i]];
dp[j] = dp[j](考虑coins[i]的组合总和)+ dp[j - coins[i]](不考虑coins[i]);

3.dp数组如何初始化

dp[0] = 1是 递归公式的基础。

4.确定遍历顺序

如果求组合数就是外层for循环遍历物品,内层for遍历背包
如果求排列数就是外层for遍历背包,内层for循环遍历物品
本题要求凑成总和的组合数,元素之间要求没有顺序,所以外层for循环是物品

class Solution {
    public int change(int amount, int[] coins) {
        int n = coins.length;
        int[][] dp = new int[n + 1][amount + 1];
        // base case
        for (int i = 0; i <= n; i++)
            dp[i][0] = 1;

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= amount; j++)
                if (j - coins[i-1] >= 0)
                    dp[i][j] = dp[i - 1][j]
                            + dp[i][j - coins[i-1]];
                else
                    dp[i][j] = dp[i - 1][j];
        }
        return dp[n][amount];
    }
}

377. 组合总和 Ⅳ

题目链接:377. 组合总和 Ⅳ

思路:
这题题目写的是组合,但是实际上是求排列。

动规五部曲 

1.确定dp数组以及下标的含义

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

2.确定递推公式

求装满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]];

3.dp数组如何初始化

dp[0] = 1

4.确定遍历顺序

求排列数外层for遍历背包,内层for循环遍历物品。

class Solution {
    public int combinationSum4(int[] nums, int target) {
        // dp数组的定义 dp[j]从数组中找出返回总和为j的组合个数
        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] + dp[i - nums[j]];
            }
        }
        return dp[target];
    }
}