这个题解使用了动态规划的思路。首先判断数组的总和是否为奇数,如果是则不可能平分成两个等和子集。然后将目标和设为总和的一半。接下来使用一个整数dp作为状态,其二进制表示中从右往左第i位表示是否存在一个和为i的子集。通过遍历数组中的每个数x,将dp中所有已经置为1的位向右移动x位,再与原dp取或,这样就在dp中记录了当前数组前缀中所有可能的子集和。如果右移后dp的最低位变为1,说明存在一个子集的和等于目标和,直接返回True。遍历结束后,如果dp最低位仍为0,说明不存在符合条件的子集划分,返回False。
时间复杂度: O(n * target)
空间复杂度: O(1)
class Solution:
def canPartition(self, nums: List[int]) -> bool:
s = sum(nums)
if s & 1:
return False
target = s >> 1
# dp的二进制数中,从右往左数,第i位表示是否存在一个和为i的子集
dp = 1 << target
for x in nums:
# 将dp中所有已经置为1的位向右移动x位,再与原dp取或
dp |= dp >> x
# 如果右移后dp的最低位变为1,说明存在一个子集的和等于目标和,直接返回True
if dp & 1:
return True
# 遍历结束后,如果dp最低位仍为0,说明不存在符合条件的子集划分,返回False
return False