Leetcode-416. 分割等和子集(经典动态规划中的背包问题)

题目

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

注意:

每个数组中的元素不会超过 100
数组的大小不会超过 200
示例 1:

输入: [1, 5, 11, 5]

输出: true

解释: 数组可以分割成 [1, 5, 5] 和 [11].

示例 2:

输入: [1, 2, 3, 5]

输出: false

解释: 数组不能分割成两个元素和相等的子集.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/partition-equal-subset-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解链接

https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/0-1-bei-bao-wen-ti-xiang-jie-zhen-dui-ben-ti-de-yo/

原始代码

class Solution(object):
    def canPartition(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        target, mod = divmod(sum(nums), 2)
        if mod != 0:
            return False

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

优化代码

class Solution(object):
    def canPartition(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        target, mod = divmod(sum(nums), 2)
        if mod != 0:
            return False
        pre = [False]*(target+1)   # 空间优化1: 由于只需要参考上一行,所以用两行数组交替即可
        cur = [False]*(target+1)
        pre[0]=True
        for i in range(1,target+1):
            if(nums[0]==i):
                pre[i]=True  # 编程技巧:本来是第一个元素应该初始化为False, 因为没有什么物品选择了以后能重量为0, 由于题目特殊,当某一行的物品独自一个满足的时候也满足,即 nums[i] = j 的时候(此时pre[j-nums[i]] = pre[0]),  因此将第一列初始化为True
                break   # 时间优化1: 由于数值递增,因此当有一个相等的时候,后面不可能相等了
        for i in range(1,len(nums)):
            for j in range(target+1):
                if(j>=nums[i]):
                    cur[j]= ( pre[j] or pre[j-nums[i]])  # 核心:状态转移方程
                else:
                    cur[j]=pre[j]
            if cur[target]:  # 时间优化2:当一列有一个为True,则这一列下面都是True了
                return True
            pre = cur[:]
        return pre[-1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值