自学内容网 自学内容网

leetcode热题100.分割等和子集(动态规划)

分割等和子集

Problem: 416. 分割等和子集

思路

我选择使用动态规划的方法来解题。我们需要判断是否可以将数组分割成两个子集,使得这两个子集的和相等。这个问题可以转化为在数组中找到一个子集,使得其和等于数组总和的一半。

解题过程

  1. 首先,我们计算数组的总和 total。如果 total 是奇数,那么我们无法将其分成两个和相等的子集,因此直接返回 False
  2. 接下来,我们将目标和 target 定为 total // 2
  3. 初始化一个二维布尔数组 dp,其中 dp[i][j] 表示前 i 个元素是否可以组成和为 j 的子集。
  4. 设置初始条件:dp[i][0]True,因为和为 0 的子集总是可以通过不选取任何元素来实现。
  5. 遍历数组,更新 dp 数组:
    • 如果当前元素 nums[i] 小于等于目标和 j,则 dp[i][j] 可以由两种情况得到:不包含当前元素(即 dp[i-1][j])或包含当前元素(即 dp[i-1][j-nums[i]])。
    • 如果当前元素 nums[i] 大于目标和 j,则 dp[i][j] 只能由不包含当前元素的情况得到,即 dp[i-1][j]
  6. 最后,检查 dp[n-1][target] 的值,判断是否可以将数组分割成两个和相等的子集。

复杂度

  • 时间复杂度:$O(n \cdot target)$,其中 n 是数组的长度,target 是数组总和的一半。
  • 空间复杂度: $O(n \cdot target)$,因为使用了一个二维数组 dp

Code

from typing import List

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        n = len(nums)
        if n < 2:
            return False

        total = sum(nums)
        if total & 1:
            return False

        target = total // 2

        if max(nums) > target:
            return False

        dp = [[False] * (target + 1) for _ in range(n)]
        for i in range(n):
            dp[i][0] = True
        
        dp[0][nums[0]] = True
        for i in range(1, n):
            for j in range(1, target + 1):
                if j >= nums[i]:
                    dp[i][j] = dp[i-1][j] | dp[i-1][j-nums[i]]
                else:
                    dp[i][j] = dp[i-1][j]

        return dp[n-1][target]


原文地址:https://blog.csdn.net/qq_51118755/article/details/140483738

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!