相信很多小伙伴刷题的时候面对力扣上近两千道题目,感觉无从下手,我花费半年时间整理了Github项目:leetcode刷题攻略。 里面有100多道经典算法题目刷题顺序、配有40w字的详细图解,常用算法模板总结,以及难点视频讲解,按照list一道一道刷就可以了!star支持一波吧!

416. 分割等和子集

题目链接:https://leetcode-cn.com/problems/partition-equal-subset-sum/

题目难易:中等

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

注意:
每个数组中的元素不会超过 100
数组的大小不会超过 200

示例 1:
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].

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

思路

这道题目初步看,是如下两题几乎是一样的,大家可以用回溯法,解决如下两题

  • 698.划分为k个相等的子集
  • 473.火柴拼正方形

这道题目是要找是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

那么只要找到集合里能够出现 sum / 2 的子集总和,就算是可以分割成两个相同元素和子集了。

本题是可以用回溯暴力搜索出所有答案的,但最后超时了,也不想再优化了,放弃回溯,直接上01背包吧。

如果对01背包不够了解,建议仔细看完如下两篇:

  • 动态规划:关于01背包问题,你该了解这些!
  • 动态规划:关于01背包问题,你该了解这些!(滚动数组)

01背包问题

背包问题,大家都知道,有N件物品和一个最多能被重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

背包问题有多种背包方式,常见的有:01背包、完全背包、多重背包、分组背包和混合背包等等。

要注意题目描述中商品是不是可以重复放入。

即一个商品如果可以重复多次放入是完全背包,而只能放入一次是01背包,写法还是不一样的。

要明确本题中我们要使用的是01背包,因为元素我们只能用一次。

回归主题:首先,本题要求集合里能否出现总和为 sum / 2 的子集。

那么来一一对应一下本题,看看背包问题如果来解决。

只有确定了如下四点,才能把01背包问题套到本题上来。

  • 背包的体积为sum / 2
  • 背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
  • 背包如何正好装满,说明找到了总和为 sum / 2 的子集。
  • 背包中每一个元素是不可重复放入。

以上分析完,我们就可以套用01背包,来解决这个问题了。

动规五部曲分析如下:

  1. 确定dp数组以及下标的含义

01背包中,dp[i] 表示: 容量为j的背包,所背的物品价值可以最大为dp[j]。

套到本题,dp[i]表示 背包总容量是i,最大可以凑成i的子集总和为dp[i]

  1. 确定递推公式

01背包的递推公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

本题,相当于背包里放入数值,那么物品i的重量是nums[i],其价值也是nums[i]。

所以递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);

  1. dp数组如何初始化

在01背包,一维dp如何初始化,已经讲过,

从dp[j]的定义来看,首先dp[0]一定是0。

如果如果题目给的价值都是正整数那么非0下标都初始化为0就可以了,如果题目给的价值有负数,那么非0下标就要初始化为负无穷。

这样才能让dp数组在递归公式的过程中取的最大的价值,而不是被初始值覆盖了

本题题目中 只包含正整数的非空数组,所以非0下标的元素初始化为0就可以了。

代码如下:

// 题目中说:每个数组中的元素不会超过 100,数组的大小不会超过 200
// 总和不会大于20000,背包最大只需要其中一半,所以10001大小就可以了
vector<int> dp(10001, 0);
  1. 确定遍历顺序

在动态规划:关于01背包问题,你该了解这些!(滚动数组)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒叙遍历!

代码如下:

// 开始 01背包
for(int i = 0; i < nums.size(); i++) {for(int j = target; j >= nums[i]; j--) { // 每一个元素一定是不可重复放入,所以从大到小遍历dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);}
}
  1. 举例推导dp数组

dp[i]的数值一定是小于等于i的。

如果dp[i] == i 说明,集合中的子集总和正好可以凑成总和i,理解这一点很重要。

用例1,输入[1,5,11,5] 为例,如图:

最后dp[11] == 11,说明可以将这个数组分割成两个子集,使得两个子集的元素和相等。

综上分析完毕,C++代码如下:

class Solution {
public:bool canPartition(vector<int>& nums) {int sum = 0;// dp[i]中的i表示背包内总和// 题目中说:每个数组中的元素不会超过 100,数组的大小不会超过 200// 总和不会大于20000,背包最大只需要其中一半,所以10001大小就可以了vector<int> dp(10001, 0); for (int i = 0; i < nums.size(); i++) {sum += nums[i];}if (sum % 2 == 1) return false;int target = sum / 2;// 开始 01背包 for(int i = 0; i < nums.size(); i++) {for(int j = target; j >= nums[i]; j--) { // 每一个元素一定是不可重复放入,所以从大到小遍历dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);}}// 集合中的元素正好可以凑成总和target if (dp[target] == target) return true;return false;      }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n),虽然dp数组大小为一个常数,但是大常数

总结

这道题目就是一道01背包应用类的题目,需要我们拆解题目,然后套入01背包的场景。

01背包相对于本题,主要要理解,题目中物品是nums[i],重量是nums[i]i,价值也是nums[i],背包体积是sum/2。

看代码的话,就可以发现,基本就是按照01背包的写法来的。

我是程序员Carl,可以找我组队刷题,也可以在B站上找到我,关注公众号代码随想录来和上万录友一起打卡学习算法,来看看,你会发现相见恨晚!

如果感觉对你有帮助,不要吝啬给一个

「代码随想录」416. 分割等和子集【动态规划】力扣详解!相关推荐

  1. LeetCode 416. 分割等和子集(动态规划)(0-1背包)

    题目描述 给定一个只包含正整数的非空数组.是否可以将这个数组分割成两个子集,使得两个子集的元素和相等. 注意: 每个数组中的元素不会超过 100 数组的大小不会超过 200 示例 1: 输入: [1, ...

  2. 代码随想录42——动态规划:0-1背包理论基础、0-1背包滚动数组、416分割等和子集

    文章目录 1.0-1背包理论基础 1.1.概述 1.2.0-1背包 1.3.二维dp数组01背包--动规五部曲 1.4.完整测试代码 2.0-1背包滚动数组 2.1.一维滚动数组 2.2.一维dp数组 ...

  3. 代码随想录算法训练营第四十二天 | 01背包问题,你该了解这些、01背包问题,你该了解这些 滚动数组、 416. 分割等和子集

    打卡第42天,搞搞01背包. 今日任务 01背包问题,你该了解这些! 01背包问题,你该了解这些! 滚动数组 416.分割等和子集 背包问题1.0 :0-1 背包 有n件物品和一个最多能背重量为w 的 ...

  4. 代码随想录算法训练营day42 | 01背包问题,你该了解这些!,01背包问题,你该了解这些! 滚动数组 , 416. 分割等和子集

    代码随想录算法训练营day42 | 背包理论基础,背包理论基础(滚动数组), 416. 分割等和子集 1.01背包理论基础 背包问题概述 01背包 二维dp数组01背包案例 2.01背包理论基础(滚动 ...

  5. 代码随想录算法训练营第42天 | 动态规划 part04 ● 背包问题二维● 背包问题滚动数组 一维 ● 416. 分割等和子集

    # 二维dp数组,01背包 1.确定dp数组以及下标的含义 dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少. 2.  gpt 解决我的困惑 3.  另外 ...

  6. 代码随想录算法训练营第四十二天-动态规划4|● 01背包问题,你该了解这些! ● 01背包问题,你该了解这些! 滚动数组 ● 416. 分割等和子集

    今天只有1道题,属于动态规划的01背包问题的应用.首先理解一下动态规划的01背包问题.推荐一个视频,动态规划DP0-1背包,这是我认为讲得最为通透的.很多讲解动态背包问题的,一上来就画二维表格,遍历背 ...

  7. 代码随想录算法训练营第45天动态规划 背包基础 1 2、 416. 分割等和子集

    文章目录 01背包基础 (二维数组) 思路 递推公式 初始化 遍历顺序 一维dp数组(滚动数组) 一维数组的递推公式 遍历顺序 LeetCode 416. 分割等和子集 思路 总结 01背包基础 (二 ...

  8. 新功能又来啦!这次是「代码搜索」和视频直播!

    不知不觉又到周五,菌菌又带着新功能来啦! 代码搜索功能发布,提升开发效率 开发一个项目,配置参数是必不可少的步骤,而项目规模越大需要配置的参数就越多.怎么样?是不是已经开始头疼了?dengdengde ...

  9. 如何排版 微信公众号「代码块」之 MarkEditor

    前段时间写过一篇文章 如何排版微信公众号「代码块」,讲的是如何使用浏览器插件 Markdown Here 来排版代码块.虽然用 Markdown Here 排版出来的样式还不错,但存在一个问题,就是代 ...

  10. 「代码家」的学习过程和学习经验分享【转】

    图灵丛书的一句话说的很好,Standing on the shoulders of giants,是的,我们一直站在巨人的肩上,我们起步都在沿着他们的轨迹前行,之后慢慢的在前人的开发基础或者规范上写出 ...

最新文章

  1. 阿里云的服务器内网互通的前提条件
  2. DR模式 mysqlABB读写分离
  3. 更新登录SAP后的LOGO
  4. 一次二次开发中的经验与教训(二)
  5. SpringBoot异常处理-@ControlleAdvice
  6. 力扣529.扫雷游戏
  7. 记录一下把域名从阿里云服务商转入到华为云
  8. doors如何导入HTML文档,DOORS使用手册.doc
  9. QT中的Singal\slot机制
  10. BFC、文档流、脱离文档流
  11. 追悼伟大的科学家史蒂芬·霍金,他留下的预言能实现吗 ?
  12. 小学生也能看懂的海伦公式推导
  13. 蒙特卡洛-马尔科夫链(MCMC)初步
  14. 1.PostgreSQL下载安装
  15. Java常用设计模式之装饰者模式
  16. 现场控制能提高交流电机的效率_凯利讯半导体
  17. 卓佳收购CP TRUST Co. Ltd.,借此加强在马来西亚纳闽的业务
  18. java以太网通讯西门子plc300_plc 400 与plc300和 300与300 以太网通讯的问题-工业支持中心-西门子中国...
  19. eolinker接口测试平台的安装部署
  20. 基于Android家庭理财系统手机软件设计

热门文章

  1. 【Java并发编程】3、DelayQueue应用场景,多考生考试
  2. 【iOS】获取应用程序本地路径
  3. IOS 的loadView 及使用loadView中初始化View注意的问题。(死循环并不可怕)
  4. (中医) 我的中医实践之路-开篇
  5. ADO.NET数据访问模式
  6. 本质矩阵 基础矩阵 单应矩阵 (3)
  7. (七)、Java异常类型及处理
  8. Java对字符串进行的操作
  9. hdu 4121 xiangqi 模拟
  10. 【分享】华为总裁任正非谈企业管理:正确的方向来自于妥协