leetcode-416. Partition Equal Subset Sum切分为两相等子数组

该博客探讨了LeetCode第416题,即判断一个包含正整数的数组是否能被划分为两个和相等的子数组。通过动态规划的方法,解释了如何使用状态压缩来优化空间复杂度,并给出了状态转移方程。
摘要由CSDN通过智能技术生成

Partition Equal Subset Sum

题目

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 1:

Input: [1, 5, 11, 5]

Output: true

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

Example 2:

Input: [1, 2, 3, 5]

Output: false

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

动态规划

这题可看作0-1背包问题的变形,将其分为两个相等的数组可以转化为从数组中选择N个元素使其和为原始数组元素和的1/2.

dp[i][j]=True: 表示对于前 i 个元素能得到其和为j.
一个数组中一部分的结果和为sum/2,那么另一部分自然也为sum/2.

状态转移时也可分为选择元素或者不选;
当j-nums[i-1]<0时,不可选,dp[i][j] = dp[i-1][j]
否则dp[i][j] = dp[i - 1][j] | dp[i - 1][j-nums[i-1]]

class Solution(object):
    def canPartition(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        ssum = 0
        for num in nums:
            ssum += num
        if (ssum%2) == 1:
            return False
        ssum =ssum // 2
        dp = [[False for j in range(ssum+1)] for i in range(len(nums)+1)]
        for i in range(len(nums)+1):
            dp[i][0] = True
        for i in range(1,len(nums)+1):
            for j in range(1,ssum+1):
                if j-nums[i-1]<0:
                    dp[i][j] = dp[i-1][j]
                else:
                    dp[i][j] = dp[i - 1][j] | dp[i - 1][j-nums[i-1]]
        return dp[len(nums)][ssum]

状态压缩

dp[i][j] = dp[i-1][j]
dp[i][j] = dp[i - 1][j] | dp[i - 1][j-nums[i-1]]
从这两个状态转移方程中可以看出dp[i][j]都是通过上一行结果而来,与本行前面的数据无关,所以可以将二维 dp 数组压缩为一维,节约空间复杂度。

class Solution(object):
    def canPartition(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        ssum = 0
        for num in nums:
            ssum += num
        if (ssum%2) == 1:
            return False
        ssum =ssum // 2
        dp = [False for j in range(ssum+1)]
        dp[0] = True
        for i in range(len(nums)):
            for j in range(ssum,-1,-1):
                if j-nums[i]<0:
                    dp[j] = dp[j]
                else:
                    dp[j] = dp[j] | dp[j-nums[i]]
        return dp[ssum]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值