题目
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例 1:
输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。
示例 2:
输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。
思路和代码
这题我一开始写的是回溯法,可惜200多个样子30多个就超时了。回溯本质就是暴力,一个个组合尝试,在进行适当的剪枝。不过有的剪枝用处不大。
together = sum(nums)
if together%2:
return False
target = together // 2
nums.sort()
path = []
ans = False
def backtrack(start,nums):
nonlocal ans
if ans == True:
return
if sum(path) > target:
return
if sum(path) == target:
ans = True
return ans
for i in range(start,len(nums)):
path.append(nums[i])
backtrack(i+1,nums)
path.pop()
backtrack(0,nums)
return ans
然后知道用动态规划,但就是想不起来怎么用,看了题解之后,这不典型的0-1背包问题。我咋怎么笨啊,题目换个马甲我就不认得了,唉。主要是看代码用看不懂了,dp[j]表示的是什么,为什么状态转移方程取最大值,为什么遍历的时候先“物品”后“容量”,为什么容量要倒序遍历…
我先重看了一遍代码随想录对一维数组实现0-1背包问题又看了一遍。推导了为什么一维动规的容量必须要从大到小,是为了保证一个物品只被放入一次。怎么保证的,讲不清楚,就是结合一个实际的例子,按照方程推一下状态就清楚了(我感觉我清楚了?)。然后为什么外层循环是物品(这题的话就是数组里的数),内层循环是容量(这题的话就是数组和的一半)?因为容量要从大到小,如果放在外层就会导致每个dp[j]只能放入一个能放进去的价值最大的物品。为啥?也是结合一个示例按照公式推了一下。
实际的例子:背包容量为4,有三个物品,每个物品的重量和价值如下:
为什么容量要从大到小?
为什么外层循环是物品,内层是容量?
结合这题代码,dp[j]就是容量为j的时候能够得到的最大的值。
class Solution:
def canPartition(self, nums: List[int]) -> bool:
value = sum(nums)
if value % 2:
return False
taregt = value // 2
n = len(nums)
dp = [0] * (taregt+1)
for i in range(n):
for j in range(taregt,nums[i]-1,-1):
dp[j] = max(dp[j],dp[j-nums[i]]+nums[i])
return dp[taregt] == taregt