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

ops/2025/1/31 12:59:40/

问题背景

给你一个 只包含正整数非空 数组 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.ppmy.cn/ops/154196.html

相关文章

动态规划(路径问题)

62. 不同路径 62. 不同路径 - 力扣&#xff08;LeetCode&#xff09; 动态规划思想第一步&#xff1a;描述状态~ dp[i][j]&#xff1a;表示走到i&#xff0c;j位置时&#xff0c;一共有多少种方法~ 动态规划思想第二步&#xff1a;状态转移方程~ 动态规划思想第三步&#xf…

微服务学习-Nacos 注册中心实战

1. 注册中心的设计思路 1.1. 微服务为什么会用到注册中心&#xff1f; 服务与服务之间调用需要有服务发现功能&#xff1b;例如订单服务调用库存服务&#xff0c;库存服务如果有多个&#xff0c;订单服务到底调用那个库存服务呢&#xff08;负载均衡器&#xff09;&#xff0…

Three.js实战项目02:vue3+three.js实现汽车展厅项目

文章目录 实战项目02项目预览项目创建初始化项目模型加载与展厅灯光加载汽车模型设置灯光材质设置完整项目下载实战项目02 项目预览 完整项目效果: 项目创建 创建项目: pnpm create vue安装包: pnpm add three@0.153.0 pnpm add gsap初始化项目 修改App.js代码&#x…

SET alter system reload

目录标题 alter system 只是 写 auto 文件SET & alter system1. **会话级别参数&#xff08;Session-level parameters&#xff09;**2. **系统级别参数&#xff08;System-level parameters&#xff09;**3. **某些特定的超级用户参数**4. **修改时生效的参数**总结&#…

Ubuntu x64下交叉编译ffmpeg、sdl2到目标架构为aarch64架构的系统(生成ffmpeg、ffprobe、ffplay)

一、编译SDL2-2.0.9 &#xff08;1&#xff09;&#xff0c; ./configure --prefix/home/z/Desktop/sdl2 --enable-sharedyes --enable-nasmno --enable-audiono --enable-ossno --enable-alsano --enable-alsa-sharedno --enable-pulseaudiono --enable-pulseaudio-sharedno …

使用 ECS服务器 和 vsCode 搭建远程开发站

SSH 连接测试 学习过 Linux 的应该对 SSH 很了解&#xff0c;使用在此不介绍 Linux 上的使用 在 Window 中打开 PowerShell 程序【此处不知道 PowerShell 可以百度一下&#xff0c;不做过多介绍】 方法一&#xff1a;按住 Shift &#xff0c;鼠标右键桌面 方法二&#xff1…

掌握Java反射:在项目中高效应用反射机制

1. 什么是Java反射&#xff1f; Java反射是一种非常强大的功能&#xff0c;允许程序在运行时动态地获取类的信息&#xff0c;甚至可以创建对象、调用方法和访问字段。简单来说&#xff0c;反射就像是让程序自己“看见”并操作自己&#xff0c;类似于自我检查和自我修改。 反射…

安装环境pytorch

Previous PyTorch Versions | PyTorch 虚拟环境中安装cuda和cudnn conda search cudatoolkit --info 找见cuda10.2 下载、安装。 conda install --use-local "D:\download\cudatoolkit-10.2.89-h74a9793_0.conda" conda search cudnn --info conda install --use-l…