416. 分割等和子集

给你一个 只包含正整数 的 非空 数组 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
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值