[LeetCode] Partition Equal Subset Sum 相同子集和分割
Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.
Note:
Both the array size and each of the array element will not exceed 100.
Example 1:
Input: [1, 5, 11, 5] Output: true Explanation: The array can be partitioned as [1, 5, 5] and [11].
Example 2:
Input: [1, 2, 3, 5] Output: false Explanation: The array cannot be partitioned into equal sum subsets.
这道题给了我们一个数组,问这个数组能不能分成两个非空子集合,使得两个子集合的元素之和相同。那么想,原数组所有数字和一定是偶数,不然根本无法拆成两个和相同的子集合,只需要算出原数组的数字之和,然后除以2,就是 target,那么问题就转换为能不能找到一个非空子集合,使得其数字之和为 target。开始博主想的是遍历所有子集合,算和,但是这种方法无法通过 OJ 的大数据集合。于是乎,动态规划 Dynamic Programming 就是不二之选。定义一个一维的 dp 数组,其中 dp[i] 表示原数组是否可以取出若干个数字,其和为i。那么最后只需要返回 dp[target] 就行了。初始化 dp[0] 为 true,由于题目中限制了所有数字为正数,就不用担心会出现和为0或者负数的情况。关键问题就是要找出状态转移方程了,需要遍历原数组中的数字,对于遍历到的每个数字 nums[i],需要更新 dp 数组,既然最终目标是想知道 dp[target] 的 boolean 值,就要想办法用数组中的数字去凑出 target,因为都是正数,所以只会越加越大,加上 nums[i] 就有可能会组成区间 [nums[i], target] 中的某个值,那么对于这个区间中的任意一个数字j,如果 dp[j - nums[i]] 为 true 的话,说明现在已经可以组成 j-nums[i] 这个数字了,再加上 nums[i],就可以组成数字j了,那么 dp[j] 就一定为 true。如果之前 dp[j] 已经为 true 了,当然还要保持 true,所以还要 ‘或’ 上自身,于是状态转移方程如下:
dp[j] = dp[j] || dp[j - nums[i]] (nums[i] <= j <= target)
有了状态转移方程,就可以写出代码了,这里需要特别注意的是,第二个 for 循环一定要从 target 遍历到 nums[i],而不能反过来,想想为什么呢?因为如果从 nums[i] 遍历到 target 的话,假如 nums[i]=1 的话,那么 [1, target] 中所有的 dp 值都是 true,因为 dp[0] 是 true,dp[1] 会或上 dp[0],为 true,dp[2] 会或上 dp[1],为 true,依此类推,完全使的 dp 数组失效了,参见代码如下:
解法一:
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = accumulate(nums.begin(), nums.end(), ), target = sum >> ;
if (sum & ) return false;
vector<bool> dp(target + , false);
dp[] = true;
for (int num : nums) {
for (int i = target; i >= num; --i) {
dp[i] = dp[i] || dp[i - num];
}
}
return dp[target];
}
};
这道题还可以用 bitset 来做,感觉也十分的巧妙,bisets 的大小设为 5001,为啥呢,因为题目中说了数组的长度和每个数字的大小都不会超过 100,那么最大的和为 10000,那么一半就是 5000,前面再加上个0,就是 5001 了。初始化把最低位赋值为1,算出数组之和,然后遍历数字,对于遍历到的数字 num,把 bits 向左平移 num 位,然后再或上原来的 bits,这样所有的可能出现的和位置上都为1。举个例子来说吧,比如对于数组 [2,3] 来说,初始化 bits 为1,然后对于数字2,bits 变为 101,可以看出来 bits[2] 标记为了1,然后遍历到3,bits 变为了 101101,看到 bits[5],bits[3],bits[2] 都分别为1了,正好代表了可能的和 2,3,5,这样遍历完整个数组后,去看 bits[sum >> 1] 是否为1即可,参见代码如下:
解法二:
class Solution {
public:
bool canPartition(vector<int>& nums) {
bitset<> bits();
int sum = accumulate(nums.begin(), nums.end(), );
for (int num : nums) bits |= bits << num;
return (sum % == ) && bits[sum >> ];
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/416
类似题目:
Partition to K Equal Sum Subset
参考资料:
https://leetcode.com/problems/partition-equal-subset-sum/
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Partition Equal Subset Sum 相同子集和分割的更多相关文章
- [LeetCode] 416. Partition Equal Subset Sum 相同子集和分割
Given a non-empty array containing only positive integers, find if the array can be partitioned into ...
- Leetcode: Partition Equal Subset Sum
Given a non-empty array containing only positive integers, find if the array can be partitioned into ...
- Leetcode ——Partition Equal Subset Sum
Question Given a non-empty array containing only positive integers, find if the array can be partiti ...
- LeetCode—— Partition Equal Subset Sum
Question Given a non-empty array containing only positive integers, find if the array can be partiti ...
- LN : leetcode 416 Partition Equal Subset Sum
lc 416 Partition Equal Subset Sum 416 Partition Equal Subset Sum Given a non-empty array containing ...
- Partition Equal Subset Sum
Given a non-empty array containing only positive integers, find if the array can be partitioned into ...
- [leetcode]416. Partition Equal Subset Sum分割数组的和相同子集
Given a non-empty array containing only positive integers, find if the array can be partitioned into ...
- Leetcode 416. Partition Equal Subset Sum
Given a non-empty array containing only positive integers, find if the array can be partitioned into ...
- [Swift]LeetCode416. 分割等和子集 | Partition Equal Subset Sum
Given a non-empty array containing only positive integers, find if the array can be partitioned into ...
随机推荐
- python类的实例方法\静态方法\类方法区别解析(附代码)
前言 搞了好久python,一直搞得不太清楚这几种类的方法,今天花时间好好测试一下,算是弄懂点皮毛吧. 三种方法的不同 先剽窃个图看一下 可以看到,实例是三种方法都可以调用的,而类只可以调用两种.所以 ...
- ThreadPool.QueueUserWorkItem的用法
代码: ThreadPool.SetMaxThreads(, ); ThreadPool.QueueUserWorkItem((obj) => { MessageBox.Show("执 ...
- OData Client Code Generator
转发. [Tutorial & Sample] How to use OData Client Code Generator to generate client-side proxy cla ...
- C#开发微信门户及应用(7)-微信多客服功能及开发集成
最近一直在弄微信的集成功能开发,发现微信给认证账户开通了一个多客服的功能,对于客户的咨询,可以切换至客服处理的方式,而且可以添加多个客服进行处理,这个在客户咨询比较多的时候,是一个不错的营销功能.微信 ...
- Yii 2.x Behavior - 类图
yii\base\Component 继承这个类的类都具备扩展行为的能力
- PHP 单例模式
一.什么是单例模式? 1.含义 作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例.它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用. 2. ...
- java web学习总结(二十九) -------------------JavaBean的两种开发模式
SUN公司推出JSP技术后,同时也推荐了两种web应用程序的开发模式,一种是JSP+JavaBean模式,一种是Servlet+JSP+JavaBean模式. 一.JSP+JavaBean开发模式 1 ...
- html和html5详解
最近看群里聊天聊得最火热的莫过于手机网站和html5这两个词.可能有人会问,这两者有什么关系呢?随着这移动互联网快速发展的时代,尤其是4G时代已经来临的时刻,加上微软对"XP系统" ...
- js获取页面url
设置或获取对象指定的文件名或路径. window.location.pathname例:http://localhost:8086/topic/index?topicId=361alert(windo ...
- SDK接入(3)之iOS内支付(In-App Purchase)接入
SDK接入(3)之iOS内支付(In-App Purchase)接入 继整理了Android平台的SDK接入过程.再来分享下iOS平台的内支付(In-App Purchase)接入,作为笔者在游戏开发 ...