链接:https://leetcode.cn/problems/partition-equal-subset-sum/solution/by-xun-ge-v-z0hr/
来源:力扣(LeetCode)
题目
示例
思路
解题思路
题目需要分割非空数组 nums 为两个数组,这个数组分割使得两个子集的元素和相等。
可以将题目转换一下为,将nums数组求和之后,除半,再在数组nums中是否可以寻找任意个元素累加和相等,元素唯一不重复选择
其实将题目转换之后和 零钱兑换 题目思路就差不多了。都是背包问题
相当于现在给我们一个容量有限背包和一堆东西,我们需要将这些东西装到背包里面,现在只需要判断能不能正好装满,我不关心里面装什么,装多少。
所以我们申请二维dp[i][j]数组,记录我们这个背包装了什么还能装什么,装没有装满,遇见东西时就有两个状态
- 没有装:dp[i][j] = dp[i-1][j],没有装我继承上一次背包状态
- 装了:
- 正好装满dp[i][j] = true
- 装了但是还没有装满:dp[i][j] = dp[i-1][j-nums[i]],东西我装了,判断一下我装了这个东西还有没有东西和我一起凑满
比如现在背包大小为5,有东西1,2,3,4(与题目无关),dp[i][j]表示背包大为j时,选择了东西i,当前背包是满(true),还是未满(false),所以dp[1][2]为true,表示我选择了东西2并且背包大小为2时,我背包满了,因此dp[2][3]=true,那么dp[2][5] = dp[2][3] + dp[1][2] = true,我背包大小为5,可以选择装东西3和东西2,当背包大小不能装下我的东西时继承i-1背包状态,因为我可以选择不装当前东西,那么背包也就没有变动,以此类推,最后返回dp[][max_j] 是否满
空间压缩
从上面可以看出来,我们并不关心背包里面装了什么地方,那么是不是没必要申请记录装东西的大小,当然是可以的,我们只关心背包能不能装满,因此我们申请dp[n]记录背包大小为n时能不能装满,但是在装东西的时候就需要从大背包开始装,因为这样可以保留上一次背包状态
总和必须为偶数,奇数/2 存在.5我们不管怎么找都不能在整数数组中找到小数
代码
空间未优化
**二维空间未优化**
bool canPartition(int* nums, int numsSize){
int sum = 0;
for(int i = 0; i < numsSize; i++)//统计和
{
sum += nums[i];
}
if(sum % 2)//是否为偶数,奇数/2 存在.5我们不管怎么找都不能在整数数组中找到小数
{
return false;
}
int dpLen = sum/2;
bool dp[numsSize][dpLen + 1];//记录背包情况
for(int i = 0; i <= dpLen; i++)//将第一个东西装入
{
if(nums[0] == i)
{
dp[0][i] = true;
}
dp[0][i] = false;
}
for(int i = 1; i < numsSize; i ++)//将其他的大小装入背包
{
for(int j = 1; j <= dpLen; j++)//更新背包情况
{
dp[i][j] = dp[i-1][j];
if(nums[i] == j)//背包大小与东西大小一样
{
dp[i][j] = true;
}
else if(nums[i] < j)
{
if(dp[i - 1][j - nums[i]] == true)//装了当前东西背包有没有足够空间
{
dp[i][j] = true;
}
}
}
}
if(dp[numsSize-1][dpLen] == true)
{
return true;
}
return false;
}
空间压缩
bool canPartition(int* nums, int numsSize){
int sum = 0;
for(int i = 0; i < numsSize; i++)
{
sum += nums[i];
}
if(sum % 2)
{
return false;
}
int dpLen = sum/2;
bool dp[dpLen + 1];
for(int i = 0; i <= dpLen; i++)
{
if(nums[0] == i)
{
dp[i] = true;
}
dp[i] = false;
}
for(int i = 1; i < numsSize; i ++)
{
for(int j = dpLen; j >= 1; j--)
{
if(nums[i] == j)
{
dp[j] = true;
}
else if(nums[i] < j)
{
if(dp[j - nums[i]] == true)
{
dp[j] = true;
}
}
}
}
if(dp[dpLen] == true)
{
return true;
}
return false;
}