【开始刷LeetCode】416. 分割等和子集
一、绪
本篇文章主要用到动态规划的思想,并且这个问题和动态规划中经典的01背包问题类似,所以我们可以套用01背包的解法求解这个问题。
01背包的问题解法我也在另外一篇博客里进行了分析解释,详情可跳转链接: 【动态规划】01背包问题(装还是不装,老子不装啦。。。老子就是菜).
二、分割等和子集
链接: 416. 分割等和子集.
(一)题目描述
解释:
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例一:
输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。
示例二:
输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。
解题思路:
//1.求出该数组的总和,判断总和除与2是否为整数
//若不为整数,则说明数组不能分割成两个元素和相等的子集,return false
//2.将该问题以01背包问题的思想求解
//(一个容量为1/2总和的背包能否刚好装满,若是能装满则说明数组能分割成两个元素和相等的子集)
//定义一个行与列的个数为(1/2总和+1)的二维dp数组,0行0列初始化为0
//从1开始遍历行列
//1行1列时,判断容量为1的背包,能否装下重量为*(nums+1)的物体
//若不能装下,此时的背包容量为这个物体前的最佳状态即可,即dp[1][1]=dp[0][1]
//若能装下,判断上一个物体时容量为(当前背包的容量-该物体质量)的背包的最佳状态质量加上该物体质量能否比当前背包所包含的质量更趋近当前背包的最大容量
//若更趋近,则改变为上一个物体时容量为(当前背包的容量-该物体质量)的背包的最佳状态质量加上该物体质量,即dp[0][1-*(nums+1)]
//否则,则保持,即dp[1][1]=dp[0][1]
//1行2列时,以此类推
//直到dp数组遍历赋值结束
//此时dp数组最后一行最后一列的数时最趋近于1/2总和,判断该数是否等于1/2总和
//若等于,则说明数组能分割成两个元素和相等的子集,return true
//否则,return false
(二)AC代码
1.一开始用了二维dp数组的解决代码
bool canPartition(int* nums, int numsSize){
int sum=0;
for(int i=0;i<numsSize;i++)
sum+=*(nums+i);
int half;
if(sum%2!=0)
return false;
else
half=sum/2;
int dp[numsSize+1][half+1];
for(int i=0;i<=numsSize;i++)
dp[i][0]=0;
for(int j=0;j<=half;j++)
dp[0][j]=0;
for(int i=1;i<=numsSize;i++){
for(int j=1;j<=half;j++){
if(j>=*(nums+i-1)){
if(dp[i-1][j] <= dp[i-1][j-*(nums+i-1)]+*(nums+i-1))
dp[i][j] = dp[i-1][j-*(nums+i-1)]+*(nums+i-1);
else
dp[i][j] = dp[i-1][j];
}
else
dp[i][j] = dp[i-1][j];
}
}
if(dp[numsSize][half] == half)
return true;
else
return false;
}
2.进行空间优化之后,用的是一维dp数组的解决代码
bool canPartition(int* nums, int numsSize){
int sum=0;
for(int i=0;i<numsSize;i++)
sum+=*(nums+i);
int half;
if(sum%2!=0)
return false;
else
half=sum/2;
int dp[half+1];
for(int i=0;i<=half;i++)
dp[i]=0;
for(int i=0;i<numsSize;i++){
for(int j=half;j>=1;j--){
if(j>=*(nums+i)){
if(dp[j] <= dp[j-*(nums+i)]+*(nums+i))
dp[j] = dp[j-*(nums+i)]+*(nums+i);
}
}
}
if(dp[half] == half)
return true;
else
return false;
}