给你一个 只包含正整数 的 非空 数组 nums
。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例 1:
输入:nums = [1,5,11,5] 输出:true 解释:数组可以分割成 [1, 5, 5] 和 [11] 。
示例 2:
输入:nums = [1,2,3,5] 输出:false 解释:数组不能分割成两个元素和相等的子集。
思路:首先算出数组的总和,若和为奇数直接返回false,因为不可能将其分成2个子集。
然后直观的思路就是暴力回溯搜索,但会超时,因此这道题需要用到动态规划中的背包思想。
每个数只能用一次,因此是0-1背包问题,在0-1背包中,dp[j] 表示: 容量为j的背包,所背的物品价值最大可以为dp[j]。在这道题中,每个元素的数值就是它的重量,同时也是它的价值。然后我们是要寻找target==sumNum/2是否存在,也就是转化成容量为target的背包是否能装满的问题了。
然后递推公式:0-1背包的递推公式为dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);在这道题中,每个元素的数值就是它的重量,同时也是它的价值。所以递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
然后就是初始化,首先dp[0]=0,容量为0不能装下任何东西,然后其余的呢,因为每次递推都会取最大值来覆盖,因此也都初始化为0。
然后是遍历顺序,需要先遍历物品,然后遍历背包的容量(从大到小)。
这道题套上0-1背包的模板就能顺利解决了。
如果没有了解过0-1背包的建议先学习一下,链接放在下面了:
problems/背包理论基础01背包-2.md · pakchoi/代码随想录 - Gitee.com
代码(Python):
class Solution(object):
def canPartition(self, nums):
sumNum = sum(nums)
if sumNum % 2 != 0: #若和为奇数,直接返回false
return False
target = sumNum / 2 #寻找有没有部分和为总和的一半
dp = [0] * (target + 1) #初始化dp数组
for i in range(1,len(nums)): #0-1背包
for j in range(target,nums[i]-1,-1):
dp[j] = max(dp[j],dp[j-nums[i]]+nums[i])
return dp[target] == target