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

完全背包理论基础

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

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

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,使得子数组的和大于等于给定的目标值。这里可以使用滑动窗口的方法来解决问题。使用两个指针来表示滑动窗口的左边界和右边界,通过移动指针来调整滑动窗口的大小,使得滑动窗口中的元素的和满足题目要求。具体实现的代码如下: ```python def minSubArrayLen(self, target: int, nums: List[int]) -> int: left = 0 right = 0 ans = float('inf') total = 0 while right < len(nums): total += nums[right] while total >= target: ans = min(ans, right - left + 1) total -= nums[left] left += 1 right += 1 return ans if ans != float('inf') else 0 ``` 以上就是第二十二算法训练营的内容。通过这些题目的练习,可以提升对双指针和滑动窗口等算法的理解和应用能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值