Leetcode Link: 416. 分割等和子集 - 力扣(LeetCode)

题目

给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

解法一

思路:从暴力递归到动态规划

  • 暴力递归 (超时),若提前对nums排序就可以了,因为排序了之后base case暗含了剪枝。
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        @cache
        def process(i, tar):
            if tar == 0:
                return True
            
            if i >= len(nums) or tar<0:
                return False
            
            p1 = process(i+1, tar)         # 不要
            p2 = process(i+1, tar-nums[i]) # 要
            return p1 or p2
        
        ssum = sum(nums)
        if ssum % 2 != 0:
            return False
        tar = ssum // 2
        return process(0, tar)
  • 动态规划
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        if sum(nums) % 2 != 0: return False
        half = sum(nums) // 2
 
        dp = [[False for _ in range(half+1)] for _ in range(len(nums))]
        # 初始化
        for i in range(len(nums)):
            dp[i][0] = True
        for tar in range(half+1):
            if tar == nums[len(nums)-1]: dp[len(nums)-1][tar] = True
        # 问题退化成用nums里的数字凑half,不再是分子集问题。
        for i in range(len(nums)-2, -1, -1):
            for tar in range(half+1):
                dp[i][tar] = (dp[i+1][tar] or dp[i+1][tar-nums[i]]) if tar-nums[i]>=0 else dp[i+1][tar]
        
        return dp[0][half]