LeetCode416. 分割等和子集

416. 分割等和子集

文章目录

    • [416. 分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum/)
      • 一、题目
      • 二、题解
        • 方法一:0-1背包二维数组
        • 方法二:0-1背包一维数组


一、题目

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

二、题解

方法一:0-1背包二维数组

步骤1:理解题目以及01 背包问题

在 01 背包问题中,我们有一系列物品,每个物品有自己的重量和价值,目标是选择一些物品放入背包中,使得背包的总重量不超过一定限制,同时所选物品的总价值最大。

题目要求将数组分割成两个子集,使得两个子集的元素和相等。这实际上就是在数组中寻找一个子集,使得这个子集的元素和等于整个数组元素和的一半。如果能找到这样的子集,那么剩余的元素的和也必然等于整个数组元素和的一半。

步骤2:将问题转化为 01 背包问题

将这道题目与 01 背包问题联系起来,可以将数组元素看作是物品的重量,而数组元素的值看作是物品的价值。我们的目标是将这些物品放入“背包”中,使得背包的总重量等于数组元素和的一半,同时价值最大。如果我们能找到一种放置物品的方式,使得背包中的物品总价值等于数组元素和的一半,那么剩余的物品总价值也必然等于数组元素和的一半,从而满足题目要求。

步骤3:套用0-1背包问题动态规划思路

在 01 背包问题中,动态规划的状态转移方程通常是:

dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i])

其中,dp[i][j] 表示在前 i 个物品中,背包的容量为 j 时的最大价值,weight[i] 表示第 i 个物品的重量,value[i] 表示第 i 个物品的价值。

在本题中,dp[i][j]

  • i: 表示考虑前 i 个元素(或前 i 个物品,类比于 01 背包问题中的物品)。
  • j: 表示目标数值,即我们希望在考虑前 i 个元素的情况下,能够凑出的元素和(或背包的容量,类比于 01 背包问题中的背包容量)。

因此,dp[i][j] 的含义是:在考虑前 i 个元素的情况下,能否凑出元素和等于 j

具体来说,dp[i][j] 可以有两种可能的取值:

  1. 如果可以在考虑前 i-1 个元素的情况下,凑出元素和等于 j,那么我们不需要使用第 i 个元素,所以 dp[i][j] = dp[i-1][j]
  2. 如果可以在考虑前 i-1 个元素的情况下,凑出元素和等于 j-nums[i],那么我们可以使用第 i 个元素,所以 dp[i][j] = dp[i-1][j-nums[i]]

步骤4:初始化和边界条件

vector<vector<int>> dp(nums.size(),vector<int>(sum/2+1,0));
for(int i = 0; i < sum/2 + 1; i++){if(nums[0] <= i){dp[0][i] = nums[0];} 
}

dp 数组的第一行中的值初始化为 0,然后对于第一行中的某个位置 dp[0][i],如果 nums[0] <= i,说明第一个元素可以放入背包中凑出和为 i,所以将其值设为 nums[0];第一列因为j本身代表元素和,因此j = 0时nums[0][j] = 0.

步骤5:填充动态规划表

我们使用两个循环来遍历动态规划数组 dp 的每个位置。其中 i 表示考虑前 i 个元素,j 表示目标数值。

  • i 循环:我们从 i = 1 开始遍历,因为 i = 0 的情况已经在初始化部分处理过了,我们从第二个元素开始考虑。
  • j 循环:我们从 j = 1 开始遍历,因为不需要考虑元素和为 0 的情况,从小到大逐步考虑不同的目标数值。

在每个位置 (i, j),我们需要根据当前的元素值 nums[i] 以及目标数值 j,判断是否可以在前 i 个元素中凑出元素和为 j。我们有两种选择:

  1. 如果当前元素值 nums[i] 大于目标数值 j,那么无法将当前元素放入凑出目标数值,因此 dp[i][j] = dp[i-1][j],即继承前一个状态的值。
  2. 如果当前元素值 nums[i]小于等于目标数值 j,我们有两种选择:
    • 选择不将当前元素放入,那么 dp[i][j] = dp[i-1][j]
    • 选择将当前元素放入,我们需要在前 i-1 个元素中寻找一种组合,使得元素和为 j-nums[i],并且将当前元素值 nums[i] 加上。因此,dp[i][j] = max(dp[i-1][j-nums[i]] + nums[i], dp[i-1][j]),即选择两种选择中的较大值。

通过这两种选择,我们可以逐步填充 dp 数组,最终得到在不同元素和的情况下,是否存在一种组合方式,使得元素和接近或等于目标数值。这就是动态规划状态转移的过程,通过不断更新 dp 数组中的值,我们可以在最后的状态中找到问题的解。

for(int i = 1; i < nums.size(); i++){for(int j = 1; j < sum/2+1; j++){if(j < nums[i]){dp[i][j] = dp[i-1][j];} else {dp[i][j] = max(dp[i-1][j-nums[i]] + nums[i], dp[i-1][j]);}}
}

步骤6:寻找答案

在填充完整个 dp 数组后,我们需要寻找一个子集,使得其元素和等于整个数组元素和的一半。我们可以在 dp[i][sum/2] 处找到这个值,如果等于 sum/2,则表示存在这样的子集,返回 true,否则返回 false

 for(int i = 0; i < nums.size(); i++){if(dp[i][sum/2] == sum/2){return true;}}return false;

总代码(和上面有一点点不同,进行了一定的变量改进)

class Solution {
public:bool canPartition(vector<int>& nums) {int sum = 0;for(int i = 0; i < nums.size(); i++){sum += nums[i];}// 如果数组元素和为奇数,无法分割成两个元素和相等的子集if(sum % 2 == 1){return false;}int target = sum / 2; // 目标数值为元素和的一半vector<vector<int>> dp(nums.size(),vector<int>(target+1,0));// 初始化第一行,表示只考虑第一个元素时的情况for(int i = 0; i < target + 1; i++){if(nums[0] <= i){dp[0][i] = nums[0];} }// 填充动态规划数组for(int i = 1; i < nums.size(); i++){for(int j = 1; j < target + 1; j++){if(j < nums[i]){// 当前元素值大于目标数值,无法放入背包dp[i][j] = dp[i-1][j];}else{// 选择放入当前元素或不放入,取较大值dp[i][j] = max(dp[i-1][j-nums[i]]+nums[i], dp[i-1][j]);}}}// 检查是否有一种组合方式使得元素和等于目标数值for(int i = 0; i < nums.size(); i++){if(dp[i][target] == target){return true;}}return false;}
};

方法二:0-1背包一维数组

思路和上面大差不差,但是可以节约空间。

class Solution {
public:bool canPartition(vector<int>& nums) {int sum = 0;for(int i = 0; i < nums.size(); i++){sum += nums[i];}// 如果数组元素和为奇数,无法分割成两个元素和相等的子集if(sum % 2 == 1){return false;}int target = sum / 2; // 目标数值为元素和的一半vector<int> dp(target+1, 0); // 使用一维数组来保存状态// 填充动态规划数组for(int i = 0; i < nums.size(); i++){// 注意循环条件是 j >= nums[i],从后往前遍历for(int j = target; j >= nums[i]; j--){// 选择放入当前元素或不放入,取较大值dp[j] = max(dp[j-nums[i]] + nums[i], dp[j]);}}// 检查是否有一种组合方式使得元素和等于目标数值if(dp[target] == target){return true;}return false;}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/54385.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频云存储/安防监控EasyCVR视频汇聚平台接入GB国标设备时,无法显示通道信息该如何解决?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

三极管NPN、PNP的区别及简单应用

目录 一、NPN、PNP三极管的概念 二、NPN、PNP三极管的区别 三、三极管NPN、PNP的简单应用 一、NPN、PNP三极管的概念 NPN型三极管&#xff1a; 由两块N型半导体和一块P型半导体组成&#xff0c;P型半导体在中间&#xff0c;两块N型半导体在两侧。 三极管是电子电路中最重要的…

elementui table 在浏览器分辨率变化的时候界面异常

异常点&#xff1a; 界面显示不完整&#xff0c;表格卡顿&#xff0c;界面已经刷新完成&#xff0c;但是表格的宽度还在一点一点变化&#xff0c;甚至有无线延伸的情况 思路&#xff1a; 1. 使用doLayout 这里官方文档有说明&#xff0c; 所以我的想法是&#xff0c;监听浏览…

Jetbrains IDE新UI设置前进/后退导航键

背景 2023年6月&#xff0c;Jetbrains在新发布的IDE&#xff08;Idea、PyCharm等&#xff09;中开放了新UI选项&#xff0c;我们勾选后重启IDE&#xff0c;便可以使用这一魔性的UI界面了。 但是前进/后退这对常用的导航键却找不到了&#xff0c;以前的设置方式&#xff08;Vi…

【C++】容器适配器stack、queue以及deque容器

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;C的学习之路 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录 前言一、什么是容器适配器1.1 stack的…

Redis 的混合持久化

RDB 相比于 AOF&#xff0c;数据恢复的速度更快&#xff0c;因为是二进制数据&#xff0c;直接加载进内存即可&#xff0c;但是 RDB 的频率不好把握。 如果频率太低&#xff0c;在两次快照期间服务器发生宕机&#xff0c;可能会丢失较多的数据如果频率太高&#xff0c;频繁写入…

研磨设计模式day12迭代器模式

目录 场景 解决方案 解决思路 代码示例 代码改造 Java实现迭代器 迭代器模式的优点 思考 何时选用 场景 大公司收购了一个小公司&#xff0c;大公司的工资系统采用List来记录工资列表&#xff0c;而小公司是采用数组&#xff0c;老板希望通过决策辅助系统来统一查看…

Android studio之GridView使用

目录 效果图&#xff1a;![在这里插入图片描述](https://img-blog.csdnimg.cn/86e4a48a71164dec82613d58b1fbaa1c.jpeg)代码&#xff1a; 效果图&#xff1a; 代码&#xff1a; UserGridviewAdapter package com.example.gridviewpro.Adapter;import android.content.Contex…

目标检测YOLO实战应用案例100讲-基于深度学习的交通标志小目标检测与识别研究

目录 前言 目标检测算法相关理论 2.1 深度学习理论基础 2.1.2卷积神经网络

202 | 抽象类、接口、内部类

抽象类 abstract 注意项 父类方法需要声明&#xff0c;但是有不确定性&#xff0c;考虑将该方法设计为抽象方法抽象方法没有实现的方法没有方法体&#xff08;跟接口的区别&#xff1f;&#xff09;抽象方法的类必须设置为抽象类&#xff0c;实现方法由其子类实现 abstract …

数学建模-建模算法(4)

python虽然不是完全为数学建模而生的&#xff0c;但是它完整的库让它越来越适合建模了。 - 线性规划&#xff1a;使用scipy.optimize.linprog()函数 python from scipy.optimize import linprogc [-1, 4] A [[-3, 1], [1, 2]] b [6, 4] x0_bounds (None, None) x1_bound…

nuxt.js框架使用swiper的5.4.5版本记录,创建广告位幻灯片

nuxt依赖 “nuxt”: “^2.15.8”, “swiper”: “^5.4.5”, “vue”: “^2.7.10”, “vue-awesome-swiper”: “^4.1.1”, 需要完成的效果是 参考地址&#xff1a;https://3.swiper.com.cn/demo/pcSlide/ nuxt代码&#xff1a; <template><div class"page&quo…

ServiceManger Binder的处理流程

陌生知识点如下&#xff1a; BinderProxy&#xff1a;是将Native层的BpBinder对象进行封装后传给Java层使用的Binder对象android_util_binder: Binder在JNI层的相关注册&#xff0c;处理&#xff0c;转换封装接口BpBinder:Binder驱动在Native层的封装。IPCThreadState&#xf…

机器学习的测试和验证(Machine Learning 研习之五)

关于 Machine Learning 研习之三、四&#xff0c;可到秋码记录上浏览。 测试和验证 了解模型对新案例的推广效果的唯一方法是在新案例上进行实际尝试。 一种方法是将模型投入生产并监控其性能。 这很有效&#xff0c;但如果你的模型非常糟糕&#xff0c;你的用户会抱怨——这…

Sentinel 控制台(集群流控管理)

规则配置 要通过 Sentinel 控制台配置集群流控规则&#xff0c;需要对控制台进行改造。我们提供了相应的接口进行适配。 从 Sentinel 1.4.0 开始&#xff0c;我们抽取出了接口用于向远程配置中心推送规则以及拉取规则&#xff1a; DynamicRuleProvider<T>: 拉取规则Dy…

jvm开启远程调试功能;idea远程debug

概述 有时候一些问题本地调试无法复现&#xff0c;这个时候可以开启jvm的远程调试功能 jar包启动 jdk8 java -agentlib:jdwptransportdt_socket,address8787,servery,suspendn -jar xxx.jarjdk11/17 java -agentlib:jdwptransportdt_socket,address*:8787,servery,suspe…

posgresql通过PL/pgSQL脚本统一修改某字段大小写

项目在做postgresql数据库适配时遇到了某些问题&#xff0c;需要统一将某个模式含id字段的全部表&#xff0c;将id字段由小写转换为大写&#xff0c;可以通过PL/pgSQL脚本实现。 先确保当前用户有足够的权限 DO $$ DECLARE current_table text;current_column text; BEGIN --…

01 消息引擎系统

本文是Kafka 核心技术与实战学习笔记 kafka的作用 kafka最经常被提到的作用是是削峰填谷&#xff0c;即解决上下游TPS的错配以及瞬时峰值流量&#xff0c;如果没有消息引擎系统的保护&#xff0c;下游系统的崩溃可能会导致全链路的崩溃。还有一个好处是发送方和接收方的松耦合…

apache2配置文件 Require all granted是什么意思

修改apache2的配置文件 /etc/apache2/apache2.conf&#xff0c;需要增加网站代码的路径&#xff0c;下列配置是什么意思呢 <Directory "/var/www/html">Options FollowSymLinksAllowOverride AllRequire all granted </Directory> 1. Options Options …

关于ios Universal Links apple-app-site-association文件 Not Found的问题

1. 背景说明 1.1 Universal Links 是什么 Support Universal Links 里面有说到 Universal Links 是什么、注意点、以及如何配置的。简单来说就是 当您支持通用链接时&#xff0c;iOS 用户可以点击指向您网站的链接&#xff0c;并无缝重定向到您安装的应用程序 大白话就是说&am…