当前位置: 首页 > article >正文

【Leetcode 热题 100】416. 分割等和子集

问题背景

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

数据约束

  • 1 ≤ n u m s . l e n g t h ≤ 200 1 \le nums.length \le 200 1nums.length200
  • 1 ≤ n u m s [ i ] ≤ 100 1 \le nums[i] \le 100 1nums[i]100

解题过程

要求分成两个子集且和相等,其实就是找到一个总和为 s u m / 2 sum / 2 sum/2 的子集,其中 s u m sum sum 表示整个集合的和。需要注意的是, s u m sum sum 必须是偶数。
此外,和为零是一种可能的状态,所以记忆化数组中的元素要初始化为 − 1 -1 1
递归入口 是 d f s ( n − 1 , s u m / 2 ) dfs(n - 1, sum / 2) dfs(n1,sum/2),表示在 [ 0 , n − 1 ] [0, n - 1] [0,n1] 的范围上找到一个和为 s u m / 2 sum / 2 sum/2 的子集。
递归边界 是 d f s ( − 1 , 0 ) = t r u e dfs(-1, 0) = true dfs(1,0)=true,表示枚举完了整个集合中的所有元素,最终能够使得剩余目标和减少到零。

翻译成递推时要注意,数组下标不能为 − 1 -1 1,所以要进行转移,将结果映射到 [ 1 , n ] [1, n] [1,n] 这个范围上。

具体实现

递归

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        if ((sum & 1) == 1) {
            return false;
        }
        int n = nums.length;
        int[][] memo = new int[n][(sum >> 1) + 1];
        for (int[] row : memo) {
            Arrays.fill(row, -1);
        }
        return dfs(n - 1, sum >> 1, nums, memo);
    }

    private boolean dfs(int i, int j, int[] nums, int[][] memo) {
        if (i < 0) {
            return j == 0;
        }
        if (memo[i][j] != -1) {
            return memo[i][j] == 1;
        }
        boolean res = j >= nums[i] && dfs(i - 1, j - nums[i], nums, memo) || dfs(i - 1, j, nums, memo);
        memo[i][j] = res ? 1 : 0;
        return res;
    }
}

递推

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        if ((sum & 1) == 1) {
            return false;
        }
        sum /= 2;
        int n = nums.length;
        boolean[][] dp = new boolean[n + 1][sum + 1];
        dp[0][0] = true;
        for (int i = 0; i < n; i++) {
            int cur = nums[i];
            for (int j = 0; j <= sum; j++) {
                dp[i + 1][j] = j >= cur && dp[i][j - cur] || dp[i][j];
            }
        }
        return dp[n][sum];
    }
}

空间优化

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        if ((sum & 1) == 1) {
            return false;
        }
        sum /= 2;
        int n = nums.length;
        boolean[] dp = new boolean[sum + 1];
        dp[0] = true;
        // minSum 表示前 i 个数和的上界,不可能超过所有这些数的总和
        int minSum = 0;
        for (int num : nums) {
            // 用这个值来初始化内层循环可以避免许多不必要的判断,想不清楚的话直接用 sum 也可以
            minSum = Math.min(minSum + num, sum);
            for (int j = minSum; j >= num; j--) {
                dp[j] = dp[j] || dp[j - num];
            }
            if (dp[sum]) {
                return true;
            }
        }
        return false;
    }
}

http://www.kler.cn/a/523253.html

相关文章:

  • LeetCode热题100中 17. 20. 53. 78. 215.
  • Base64详解
  • Android createScaledBitmap与Canvas通过RectF drawBitmap生成马赛克/高斯模糊(毛玻璃)对比,Kotlin
  • 在无sudo权限Linux上安装 Ollama 并使用 DeepSeek-R1 模型
  • OpenEuler学习笔记(十五):在OpenEuler上搭建Java运行环境
  • SQL教程-基础语法
  • 在Windows下安装Ollama并体验DeepSeek r1大模型
  • LangChain概述
  • 开关电路汇总
  • AI软件栈:LLVM分析(一)
  • kafka消费者详细介绍(超级详细)
  • 02-机器学习-核心概念
  • games101-(5/6)
  • 蓝桥云课下载(jdk11、eclipse、idea)
  • 机器人抓取与操作概述(深蓝)——1
  • C++ | 红黑树
  • 2025年01月28日Github流行趋势
  • qwen2.5-vl:阿里开源超强多模态大模型(包含使用方法、微调方法介绍)
  • 怎样在PPT中启用演讲者视图功能?
  • 苍穹外卖使用MyBatis-Plus
  • WSL安装CUDA
  • 大模型本地部署流程介绍
  • 变压器的漏感
  • WSL 安装cuDNN
  • 基于PyQt设计的智能停车管理系统
  • 计算机毕业设计Django+Tensorflow音乐推荐系统 机器学习 深度学习 音乐可视化 音乐爬虫 知识图谱 混合神经网络推荐算法 大数据毕设