题目链接:https://leetcode.com/problems/partition-equal-subset-sum/#/description
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:
- Each of the array element will not exceed 100.
- The array size will not exceed 200.
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.
方法一(超时):
class Solution{
public:
bool canPartition(vector<int>& nums)
{
int nums_sum=0;
for(auto num:nums)
nums_sum+=num;
if(nums_sum%2!=0)
return false;
int half_nums_sum=nums_sum/2;
return dfs(nums,half_nums_sum,0,0);
}
bool dfs(vector<int>& nums,int half_nums_sum,int tmp_sum,int start)
{
if(tmp_sum==half_nums_sum)
{
return true;
}
for(int i=start;i<nums.size();i++)
{
if(tmp_sum>half_nums_sum)
break;
if(dfs(nums,half_nums_sum,tmp_sum+nums[i],i+1))
return true;
}
return false;
}
};
方法二:
思路: 显然,如果原数组所有元素之和为偶数,才有可以把数组拆成两个相等的子集合,令target为原数组元素之和的一半。res[ j ]表示和为j的数组是否存在,
因此可以得到以下递推公式:res[ j ]=res[ j ] || res[ j - nums[ i ]] 。如果最终res[ target ]为true,说明存在。
class Solution{
public:
bool canPartition(vector<int>& nums)
{
int sum=0;
for(auto num:nums)
sum+=num;
if(sum%2!=0)
return false;
int target=sum/2;
vector<bool> res(target+1,false);
res[0]=true;
for(int i=0;i<nums.size();i++)
{
for(int j=target;j>=nums[i];j--)
{
res[j]=res[j]||res[j-nums[i]];
}
}
return res.back();
}
};
方法三:
思路:显然,如果原数组所有元素之和为偶数,才有可以把数组拆成两个相等的子集合,令target为原数组元素之和的一半。令res[ i ][ j ]表示最大元素之和为j,取前i个数字的子元素相加,得到的最大和。递推公式为res[ i ][ j ]=max( res[ i-1 ][ j ] , res [ i-1 ][ j- nums[ i ] ] + nums[ i ] ) ,最终,如果 res[ nums.size()-1 ][ target ] = target ,返回 true。
class Solution{
public:
bool canPartition(vector<int>& nums)
{
int sum=0;
for(auto num:nums)
sum+=num;
if(sum%2!=0)
return false;
int target=sum/2;
vector<vector<int>> res;
res.resize(nums.size());
for(int i=0;i<nums.size();i++)
res[i].resize(target+1);
for(int i=nums[0];i<=target;i++)
res[0][i]=nums[0];
for(int i=1;i<nums.size();i++)
{
for(int j=nums[i];j<=target;j++)
{
res[i][j]=max(res[i-1][j],res[i-1][j-nums[i]]+nums[i]);
}
}
if(res[nums.size()-1][target]==target)
return true;
else
return false;
}
};