416 分割等和子集
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意:
每个数组中的元素不会超过 100
数组的大小不会超过 200
示例 1:
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
示例 2:
输入: [1, 2, 3, 5]
输出: false
解释: 数组不能分割成两个元素和相等的子集.
思路
判断是否有等和子集,对数组求和,那么问题转化为,在数组是否有一个序列的和等于数组和的一半
问题变成了一个01背包问题;
利用动态规划来求解,普通解法是建立一个二维数组
(dp[i][j]) 表示从(0)到(i)之间是否存在一种方案使得和为(j) 初始是 0即false;
- 解决边界问题
(dp[i][0] = true) : 因为当和为(0)的时候,数组下标(0)到(i)之间存在一种方案使得 和为(0) (什么元素都不选)
(dp[0][nums[0]] = true) : 因为当和为(nums[0])的时候,选择(nums[0])为方案
- 解决递推问题
(if(j>=nums[i])) 那么(nums[i]) 可以不被选取,也可以被选取。只需要将两者情况取或(只要有一个为true 则dp[i][j]为true):
(dp[i][j] = dp[i-1][j] | dp[i][j-nums[i]];)
(if(j<nums[i])) 那么该元素不被选取:
(dp[i][j] = dp[i-1][j];)
class Solution {
public:
bool canPartition(vector<int>& nums) {
int n = nums.size();
if(n < 2) return false;
int sum = accumulate(nums.begin(),nums.end(),0);
int MaxNum = *max_element(nums.begin(),nums.end());
//判断sum是否为奇数,按位与 最后一位是0 则为偶数,为1 则为奇数
if(sum & 1) return false;
int target = sum/2; //转化为 0 1 背包问题,即判断数组中是否存在和为target 的序列
if(MaxNum > target) return false;
//定义动态规划数组 dp[i][j] 表示从0到i之间 有没有和为j的序列
vector<vector<int> > dp(n,vector<int> (target+1,0));
for(int i=0;i<n;i++)
{
dp[i][0] = true;
}
dp[0][nums[0]] = true;
for(int i =1;i<n;i++)
{
int num = nums[i];
for(int j=1;j<=target ;j++)
{
if(j>=num)
{
dp[i][j] = dp[i-1][j] | dp[i-1][j-num];
}
else
{
dp[i][j] = dp[i-1][j];
}
}
if(dp[i][target]) return true;
}
return dp[n-1][target];
}
};
优化空间
把dp二维数组优化为一维的,这是因为每一次状态转移,dp[i][j]的值只与上一行数组有关。
class Solution {
public:
bool canPartition(vector<int>& nums) {
int n = nums.size();
if(n < 2) return false;
int sum = accumulate(nums.begin(),nums.end(),0);
int MaxNum = *max_element(nums.begin(),nums.end());
//判断sum是否为奇数,按位与 最后一位是0 则为偶数,为1 则为奇数
if(sum & 1) return false;
int target = sum/2; //转化为 0 1 背包问题,即判断数组中是否存在和为target 的序列
if(MaxNum > target) return false;
vector<int> dp(target+1,0);
dp[0] = true;
if(nums[0] <= target)
dp[nums[0]] = true;
for(int i=1;i<n;i++)
{
for(int j = target;nums[i] <= j; j--)
{
if(dp[target])
{
return true;
}
dp[j] = dp[j] | dp[j - nums[i]];
}
}
return dp[target];
}
};
链接
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/partition-equal-subset-sum