个人技术分享

完全背包理论基础

  • 每个物品可以使用无数次

  • 和01背包的区别:

    • 1.因为每个物品可以使用无限次,所以要将遍历背包的顺序改成正序遍历

    • 2.完全背包中,先遍历背包还是先遍历物品都可以

      • 【注意】前提条件是纯完全背包问题

LeetCode 518 零钱兑换II

题目链接:518. 零钱兑换 II - 力扣(LeetCode)

【解题思路】

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

    • dp[j]的定义是:装满容量为j的背包有dp[j]种方法

    • 本题最终要求的是dp[amount]

  • 2.确定递推公式

    • dp[j]+=dp[j-coins[i]]

  • 3.确定dp数组如何初始化

    • dp[0]=1

      • 因为要做累加,所以不能初始化为0

    • 非0下标初始为0

  • 4.确定遍历顺序

    • 先遍历物品:

      • 再遍历背包:

        • 递推公式

    • Carl说先遍历物品是组合数,先遍历背包是排列数、对于这点,我的理解是:

      • 先遍历物品后遍历背包:

        • 1)外层固定物品1,进入内层循环

        • 2)背包容量不断增加

          • 物品1被重复添加进不同容量的背包中,直到背包容量遍历完毕

        • 3)背包容量遍历完毕后,执行下一次循环,开始添加物品2

          • 物品1已经被添加进每一个不同容量的背包里,因此物品2肯定会在物品1之后

      • 先遍历背包后遍历物品:

        • 1)外层循环固定背包容量

          • 在大小固定的背包里循环遍历添加物品,直到物品全遍历一次

        • 2)物品遍历结束,外层背包容量+1

          • 此时仍要执行内层循环,再次遍历一遍物品

          • 可能会出现如下情况:

            • 在上一轮遍历到物品3时,当前容量的背包已经没有办法塞入物品3,因此背包里此时有物品1和物品2

              • 在当前轮遍历的时候发现增加了容量的背包可以再添加一个物品1,就会有【物品1,物品2,物品1】这样的情况,所以很可能会有物品1出现在物品2之类的情况

  • 5.举例推导dp数组

    • 手动推导一下答案,然后将数组打印出来,看看每个状态是否是按照我们的思路进行转移的

【解题步骤】

  • 1.创建一个dp数组,大小为amount+1

  • 2.初始化dp数组,dp[0]= 1

  • 3.先遍历物品,再遍历背包:

    • 递推公式

  • 4.return dp[amount]

【代码部分】

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

LeetCode 474 组合总和IV

题目链接:377. 组合总和 Ⅳ - 力扣(LeetCode)

【解题思路】

  • 本题说是组合总和,但其实求的是排列数

    • 因为(1,2,1)和(1,1,2)算两个组合

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

    • dp[j]的定义是:装满容量为j的背包有dp[j]种方法

    • 本题最终要求的是dp[amount]

  • 2.确定递推公式

    • dp[j]+=dp[j-coins[i]]

  • 3.确定dp数组如何初始化

    • dp[0]=1

      • 因为要做累加,所以不能初始化为0

    • 非0下标初始为0

  • 4.确定遍历顺序

    • 先遍历背包:

      • 再遍历物品:

        • 递推公式

    • 因为本题求的是排列数

    • Carl说先遍历物品是组合数,先遍历背包是排列数,对于这点,我的理解是:

      • 先遍历物品后遍历背包:

        • 1)外层固定物品1,进入内层循环

        • 2)背包容量不断增加

          • 物品1被重复添加进不同容量的背包中,直到背包容量遍历完毕

        • 3)背包容量遍历完毕后,执行下一次循环,开始添加物品2

          • 物品1已经被添加进每一个不同容量的背包里,因此物品2肯定会在物品1之后

      • 先遍历背包后遍历物品:

        • 1)外层循环固定背包容量

          • 在大小固定的背包里循环遍历添加物品,直到物品全遍历一次

        • 2)物品遍历结束,外层背包容量+1

          • 此时仍要执行内层循环,再次遍历一遍物品

          • 可能会出现如下情况:

            • 在上一轮遍历到物品3时,当前容量的背包已经没有办法塞入物品3,因此背包里此时有物品1和物品2

              • 在当前轮遍历的时候发现增加了容量的背包可以再添加一个物品1,就会有【物品1,物品2,物品1】这样的情况,所以很可能会有物品1出现在物品2之类的情况

  • 5.举例推导dp数组

    • 手动推导一下答案,然后将数组打印出来,看看每个状态是否是按照我们的思路进行转移的

【解题步骤】

  • 1.创建一个dp数组,大小为amount+1

  • 2.初始化dp数组,dp[0]= 1

  • 3.先遍历物品,再遍历背包:

    • 递推公式

  • 4.return dp[amount]

【代码部分】

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