416. Partition Equal Subset Sum -Medium

Question

Given a non-empty array 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.

Note:
Each of the array element will not exceed 100.
The array size will not exceed 200.

给定一个非空正整数的列表,将其划分为两个子集,判断是否存在两个子集的总和相等的情况

Example

Input: [1, 5, 11, 5]

Output: true

Explanation: The array can be partitioned as [1, 5, 5] and [11].


Input: [1, 2, 3, 5]

Output: false

Explanation: The array cannot be partitioned into equal sum subsets.

Solution

  • 第一种非常容易想到的是DFS+记忆化。因为从源列表中划分两个总和相等的子集,那么只要任意个元素的总和达到源列表总和的一半即可(target = sum(originSetList) / 2),所以我们通过深度优先搜索遍历整个列表,同时为了防止重复计算,我们保存中间变量

    class Solution(object):
        def canPartition(self, nums):
            """
            :type nums: List[int]
            :rtype: bool
            """
            s = sum(nums)
            # 如果总和不是偶数则不可能分成两个总和相等的子集
            if s % 2 != 0: return False
            self.memory = {}
            return self.solve(nums, int(s / 2))
    
        def solve(self, nums, target):
            # 如果保存过当前情况,直接返回
            if target in self.memory:
                return self.memory[target]
    
            # 如果已经遍历完源列表或者已遍历的元素总和已经大于target则代表不存在这样的子集
            # target < 0比较重要,这相当于剪枝的过程,如果不添加这行,运行总时间需要3000多毫秒,而添加后只需要60多毫秒
            if len(nums) == 0 or target < 0: return False
            # 如果当前子集总和刚好等于target则代表已找到划分的两个子集
            if target == 0: return True
    
            # 回溯过程
            for index, value in enumerate(nums):
                # 保存返回的值
                if self.solve(nums[:index] + nums[index + 1:], target - nums[index]):
                    self.memory[target] = True
                    return True
                else: self.memory[target] = False
            # 如果搜索完所有情况仍然没有找到那么返回False代表不存在这种情况
            return False
  • 这道题还可以用动态规划做,虽然耗费的时间比剪枝过的dfs长。思路如下:如果target是由任意个元素组成,那么我们就可以划分两个总和相等的子集。而如果任意个元素总和i是由任意个元素组成的,那么加上列表元素i + nums[j]仍然由任意个元素组成的。假设dp[i]代表i是否是任意个元素的总和,由此我们得到递推式:d[i] = d[i - nums[j]] or d[i],在遍历列表nums的过程中,我们需要更新[nums[j], target]之间的值

    class Solution(object):
        def canPartition(self, nums):
            """
            :type nums: List[int]
            :rtype: bool
            """
            s = sum(nums)
            if s % 2 != 0: return False
            target = int(s / 2)
            # 默认dp[0]为True以保证d[num[j]]为True
            dp = [True] + [False] * target
            for n in nums:
                # 这里的更新需要从target到n,否则会出现更新错误
                for index in range(target, n - 1, -1):
                    dp[index] = dp[index] or dp[index - n]
            return dp[target]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值