416. Partition Equal Subset Sum

Partition Equal Subset Sum - LeetCode

Given a non-empty array nums containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.

Example 1: Input: nums = [1,5,11,5] Output: true Explanation: The array can be partitioned as [1, 5, 5] and [11].

Example 2: Input: nums = [1,2,3,5] Output: false Explanation: The array cannot be partitioned into equal sum subsets.


  • code
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        total_sum = sum(nums)
        if total_sum % 2 != 0: return False
        
        @lru_cache(maxsize=None)
        def dp(i, subset_sum):
            if subset_sum == 0: return True
            if i == len(nums) or subset_sum < 0: return False
            return dp(i + 1, subset_sum - nums[i]) or dp(i + 1, subset_sum)
        
        return dp(0, total_sum // 2)
  • code written memo
class Solution:
    def canPartition(self, nums):
        s, memo = sum(nums), {0: True}
        if s & 1: return False
        def dp(i, x):
            if x < 0: return False
            if x not in memo:
                memo[x] = False
                for j in range(i, len(nums)):
                    if dp(j+1, x-nums[j]):
                        memo[x] = True
                        break
            return memo[x]
        return dp(0, s >> 1)
  • code bottom up, dp[i][j] choose from nums[i] to the end, check if exists a subset with sum j
class Solution:
    def canPartition(self, nums):
        s = sum(nums)
        if s & 1: return False
        half = s >> 1
        dp = [([False] * (half + 1)) for _ in range(len(nums) + 1)]
        
        for i in range(len(nums) + 1): 
            dp[i][0] = True 
            
        for i in range(len(nums) - 1, -1, -1):
            for each_sum in range(half + 1):
                if each_sum >= nums[i]:
                    dp[i][each_sum] = dp[i+1][each_sum - nums[i]] or dp[i+1][each_sum]
                else:
                    dp[i][each_sum] = dp[i+1][each_sum]
                
                
        return dp[0][-1]
  • code
class Solution:
    def canPartition(self, nums):
        s = sum(nums)
        if s & 1: return False
        half = s >> 1
        dp = [False] * (half + 1)
        dp[0] = True            
        for i in range(len(nums) - 1, -1, -1):
            for each_sum in range(half, -1, -1):
                if each_sum >= nums[i]:
                    dp[each_sum] = dp[each_sum] or dp[each_sum - nums[i]]
            if dp[half]: return True
                
        return False
  • code bottom up, dp[i][j]=true if the sum j can be formed by array elements in subset nums[0]..nums[i],otherwise false
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        # find sum of array elements
        total_sum = sum(nums)

        # if total_sum is odd, it cannot be partitioned into equal sum subsets
        if total_sum % 2 != 0:
            return False
        subset_sum = total_sum // 2
        n = len(nums)

        # construct a dp table of size (n+1) x (subset_sum + 1)
        dp = [[False] * (subset_sum + 1) for _ in range(n + 1)]
        dp[0][0] = True
        for i in range(1, n + 1):
            curr = nums[i - 1]
            for j in range(subset_sum + 1):
                if j < curr:
                    dp[i][j] = dp[i - 1][j]
                else:
                    dp[i][j] = dp[i - 1][j] or dp[i - 1][j - curr]
        return dp[n][subset_sum]
  • code dp

after each pass of num

#1 [True, True, False, False, False, False, False, False, False, False, False, False] #5 [True, True, False, False, False, True, True, False, False, False, False, False] #11 [True, True, False, False, False, True, True, False, False, False, False, True] #5 [True, True, False, False, False, True, True, False, False, False, True, True]

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        total_sum = sum(nums)
        if total_sum % 2 != 0: return False
        sub_sum = total_sum // 2
        
        dp = [False] * (sub_sum + 1)
        dp[0] = True # without any num the sum is 0
        for cur in nums:
            for j in range(sub_sum, cur - 1, -1):
                dp[j] = dp[j] or dp[j - cur]
            if dp[sub_sum] == True: return True
            
            
        # return dp[sub_sum]        
        return False