416. 分割等和子集【动态规划】

题目描述

给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

示例 1:

输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。

示例 2:

输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。

提示:

1 <= nums.length <= 200
1 <= nums[i] <= 100

解题思路

本题要求把数组分成两个等和的子集,相当于找到一个子集,其和为 sum / 2,这个 sum / 2 就是 target(target 间接给出)。

于是转化为是否可以用 nums 中的数组合和成 target,01 背包问题,外层循环为选择池 num: nums,内层循环为 target。

dp[i] 表示是否存在和为 i 的 num 组合。

  • 外层遍历 nums 每个 num;
  • 内层遍历 target(由大到小)。

对于元素之和等于 i - num 的每一种组合,在最后添加 num 之后即可得到一个元素之和等于 i 的组合,因此dp[i] 依赖于 dp[i - num],并且在计算 dp[i - num] 时,要保证索引较小的元素值不被覆盖,需要后向更新 dp[i],并且当 i - num < i 时, dp[i] 已经更新过,于是:

dp[i] = dp[i] || dp[i - num]

对于特例:如果 sum 为奇数,那一定找不到符合要求的子集,返回 False。
对于边界条件,我们定义 dp[0] = true 表示当 i - num = 0,存在一个 num 和为 i。
最后返回 dp[target]。

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for (int n:nums) {
            sum += n;
        }
        if ((sum & 1) == 1) {
            return false;
        }
        int target = sum / 2;
        boolean[] dp = new boolean[target+1];
        dp[0] = true;
        for (int num : nums) {
            for (int i = target;i >= num;i--) {
                dp[i] = dp[i] || dp[i-num];
            }
        }
        return dp[target];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值