【力扣hot100题】(088)分割等和子集
果然越来越难了,真的想了好久,最后看答案才发觉这是01背包问题的变种。
先去看了01背包问题,将体积和质量不等的物体塞进容积固定的背包中,求质量最大的装法。方法是维护一个二维数组,两个维度一个代表遍历到第几个物体,一个代表占用空间,数组内容是背包内总质量。每次遍历一个物体,然后遍历上一个物体占用空间,如果剩下的空间能塞入当前物体那进行如下状态转换:
总质量[当前物体][截止至上一个物体占用的空间+该物体占用空间]=总质量[上一物体][截止至上一物体占用的空间]+当前物体质量。
于是这道题也可以用类似的思路。
不过二维数组用bool类型就可以了,只需要检查截止至物体能不能占满这个空间。
状态转换方程:(放入当前物体的情况)
是否能占满[当前物体][截止至上一物体占用的空间+该物体占用的空间]=是否占满[上一物体][截止至上一物体占用的空间]
并且:
是否能占满[当前物体][截止至上一物体占用的空间]=是否占满[上一物体][截止至上一物体占用的空间]
(不放当前物体的情况)
如果上一物体可以占满这个空间,那么加上当前物体就可以占满上一空间+这一物体空间的空间。
这样的话每次都能保留是否放入之前的物体的结果。
class Solution {
public:
bool canPartition(vector<int>& nums){
int sum=0;
for(int i=0;i<nums.size();i++) sum+=nums[i];
if(sum%2==1) return 0;
else sum/=2;
bool a[201][20000];
memset(a,0,sizeof(a));
for(int i=1;i<nums.size();i++){
for(int j=0;j<=sum;j++){
if(a[i-1][j]==1||j==0){
a[i][j]=1;
a[i][j+nums[i]]=1;
}
}
if(a[i][sum]==1) return 1;
}
return 0;
}
};
其实应该是可以优化空间复杂度的,因为每个物体只需要用到上一物体的数组。
想了一会怎么才能不重复加入元素最终看了答案,原来从大到小遍历就可以了,这样每次只会加入增大的元素,不会产生重复加入的问题。
class Solution {
public:
bool canPartition(vector<int>& nums){
int sum=0;
for(int i=0;i<nums.size();i++) sum+=nums[i];
if(sum%2==1) return 0;
else sum/=2;
bool a[20000];
memset(a,0,sizeof(a));
for(int i=1;i<nums.size();i++){
for(int j=sum;j>=0;j--){
if(a[j]==1||j==0) a[j+nums[i]]=1;
}
if(a[sum]==1) return 1;
}
return 0;
}
};