【LeetCode】分割等和子集 [M](动态规划)

166 篇文章 0 订阅

416. 分割等和子集 - 力扣(LeetCode)

一、题目

给你一个 只包含正整数 的 非空 数组 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

二、代码

class Solution {
    public boolean canPartition(int[] nums) {
        // 计算整个数组的累加和
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        // 如果累加和是奇数,那么不可能平分,返回false
        if ((sum & 1) != 0) {
            return false;
        }
        // 将累加和除以二
        sum >>= 1;

        // dp[i][rest]:表示来到i位置尝试,还剩下rest没有凑出来,这种情况能否凑出来整个数组累加和的一半
        // 1  true
        // -1 false
        // 0 还未赋值
        int[][] dp = new int[nums.length + 1][sum + 1];

        // 递归求解,返回能不能在nums数组中找到一个集合可以凑出来累加和的一半
        return process(sum, nums, 0, dp);
    }

    // 当前还剩下rest没有凑出,此时已经尝试到i位置了
    public boolean process(int rest, int[] nums, int i, int[][] dp) {
        // 如果当前情况已经计算过了,直接返回答案
        if (dp[i][rest] != 0) {
            return dp[i][rest] == 1;
        }

        // 如果剩余为0,说明凑出来了,返回true
        if (rest == 0) {
            // 赋值
            dp[i][rest] = 1;
            return true;
        // 剩余没凑出来的不为0
        } else {
            // 如果此时已经把所有的情况都尝试过了,还没有凑出数组累加和的一半,说明无法凑出,返回false
            if (i == nums.length) {
                // 赋值
                dp[i][rest] = -1;
                return false;
            // 还没有遍历完,继续尝试
            } else {
                // 情况一:不选择i位置的数,直接去下个位置做选择
                boolean p1 = process(rest, nums, i + 1, dp);
                // 情况二:选择i位置的数,剩余没凑出来的数就是rest - nums[i]
                boolean p2 = false;
                // 需要帮正选择nums[i]后,凑出来的数不能超过rest
                if (rest - nums[i] >= 0) {
                    p2 = process(rest - nums[i], nums, i + 1, dp);
                }
                // 只要是两种情况有能成的,就返回true
                if (p1 || p2) {
                    // 赋值
                    dp[i][rest] = 1;
                    return true;
                } else {
                    // 赋值
                    dp[i][rest] = -1;
                    return false;
                }
            }
        }
    }
}

三、解题思路 

就是一道背包问题,详细见注释。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值