LCR 101. 分割等和子集——力扣——背包问题、动态规矩

问题描述

代码展示

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        if len(nums) <= 1:
            return False
        
        total_sum = sum(nums)
        if total_sum % 2 != 0:  # 总和为奇数,无法分成两个相等的子集
            return False
        
        target_sum = total_sum // 2
        dp = [[False] * (target_sum + 1) for _ in range(len(nums) + 1)]
        
        # 初始化第一列
        for i in range(len(nums) + 1):
            dp[i][0] = True
        
        for i in range(1, len(nums) + 1):
            for j in range(1, target_sum + 1):
                dp[i][j] = dp[i-1][j]
                if j >= nums[i-1]:
                    dp[i][j] = dp[i][j] or dp[i-1][j-nums[i-1]]
        
        return dp[len(nums)][target_sum]

这段代码实现了一个判断给定数组是否可以被划分成两个和相等的子集的功能。

首先,如果数组长度小于等于1,则无法划分,直接返回False。

然后,计算数组中所有元素的总和,如果总和为奇数,则无法划分成两个相等的子集,直接返回False。

接下来,计算目标和,即总和的一半。创建一个二维的布尔型动态规划数组dp,其中dp[i][j]表示前i个元素是否可以组成和为j的子集。

然后,初始化动态规划数组的第一列,将其设为True。这是因为当目标和为0时,任何元素都可以不选,所以前i个元素都可以组成和为0的子集。

接着,遍历数组元素,对于每个元素nums[i-1],在目标和范围内(从1到target_sum),更新动态规划数组。对于每个位置(i, j),如果当前元素不选,则该位置的值与上一行相同,即dp[i][j] = dp[i-1][j];如果当前元素选择了,并且剩余和等于当前位置的值减去当前元素的值,则该位置的值为True,即dp[i][j] = dp[i-1][j-nums[i-1]]

最后,返回动态规划数组的最后一个位置的值,即dp[len(nums)][target_sum],表示前len(nums)个元素是否可以组成和为目标和的子集。

 

背包问题和动态规划问题

这段代码考察的知识点是动态规划(Dynamic Programming)和背包问题(Knapsack Problem)。

动态规划是一种解决问题的方法,它通过将问题分成更小的子问题,并保存子问题的解,从而避免重复计算,提高效率。这段代码中使用了动态规划来解决背包问题。

背包问题是一个经典的组合优化问题,通常有两种变体:0-1背包问题和完全背包问题。这段代码涉及的是0-1背包问题,即每个物品只能选择取或不取。

在这段代码中,给定一个整数数组nums,我们需要判断能否将其划分为两个和相等的子集。首先,我们计算数组的总和total_sum。如果总和为奇数,那么无法将其划分为两个相等的子集,直接返回False。

然后,我们将目标和target_sum设置为总和的一半。创建一个二维的动态规划表dp,dp[i][j]表示前i个物品中是否存在一种方式使得和为j。初始化第一列为True,因为当j为0时,任何物品都可以组成和为0的子集。

接下来,使用两层循环遍历数组nums和目标和target_sum。对于每个元素nums[i-1],我们有两种选择:取它或不取它。如果当前和j大于等于nums[i-1],那么可以选择取这个元素,使得dp[i][j]为True;否则,不取这个元素,保持dp[i][j]不变。最终,返回dp[len(nums)][target_sum]的结果,即是否存在一种方式使得前len(nums)个物品的和为target_sum。

这段代码使用动态规划的思想解决了0-1背包问题,判断了数组能否被划分为两个和相等的子集。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值