题目
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意:
每个数组中的元素不会超过 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]