这道题可以转化为0-1背包问题去求解的;
这道题间接可以变为:我们能不能找到一些数令所有数的和 为整个数组和的一半?
设d[i][j]:能否在0-i区间的数组中找到和为j的数
单挑出来 nums[i],对于nums[i],我们有两种选择:
选择nums[i]:
如果选择nums[i] ,那么我们 就要看d[i-1][j-nums[i]]的值是否为true
若为true,那么d[i][j]的值也为true
不选择nums[i]:
不选择nums[i],那么d[i][j]的值就为d[i-1][j]的值
那么状态转转移方程为
d[i][j] = d[i-1][j] or d[i-1][j-nums[i]]
考虑边界值,需要保证j - nums[i] >= 0,也就是 j>= nums[0]
i其实可以从1开始循环;为什么呢?因为i=0的时候,相当于选取的数只有第一个数字,那么唯一为true的地方就是 j = nums[0]的地方,其他肯定都为0
代码:
class Solution:
def canPartition(self, nums: List[int]) -> bool:
length = len(nums)
if length == 1:
return False
#算出数组的总和
sum = 0
for i in nums:
sum += i
#如果数组总和的一半为奇数,那么可以直接不用看了
if sum%2 != 0:
return False
target = sum//2
num = [] #保存最后的结果 list[list[]]
#构建初始表
for i in range(0,length):
new = [False for _ in range(0,target+1)]
num.append(new)
#num[0][nums[0]] = True
for i in range(0,len(nums)):
for j in range(0,target+1):
if j == nums[i]:
num[i][j] = True;
continue;
if j >= nums[i]:
num[i][j] = num[i-1][j] or num[i-1][j-nums[i]]
else:
num[i][j] = num[i-1][j]
return num[length - 1][target]