目录
题目描述:给你一个 只包含正整数 的 非空 数组
nums
。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
将数组分为两个和相等的子集,通过遍历整个数组求出数组和,除以2的结果就是一个子集和,只要找到一个子集等于和的一半,另一个子集和一定与其相等。
要注意:如果数组和不能被2整除,那么一定不能进行分割!
回溯(超时)
将问题转化为在数组中寻找是否有 元素和==数组和的一半 的问题!
//回溯
int* path;
int path_num;
bool backtricking(int* nums,int numsSize,int startIndex,int target){
if(target==0) return true;
if(target<0||numsSize<=startIndex) return false;
for(int i=startIndex;i<numsSize;i++){
path[path_num++]=nums[i];
target-=nums[i];
if(backtricking(nums,numsSize,i+1,target)){
return true;
}else{
path_num--;
target+=nums[i];
}
}
return false;
}
bool canPartition(int* nums, int numsSize){
int sum=0;
for(int i=0;i<numsSize;i++){
sum+=nums[i];
}
if(sum%2!=0) return false;
sum/=2;
path=(int*)malloc(sizeof(int)*numsSize);
path_num=0;
return backtricking(nums,numsSize,0,sum);
}
二维数组
将问题转化为0-1背包问题
bool canPartition(int* nums, int numsSize){
if(numsSize==1) return false;
int sum=0;
for(int i=0;i<numsSize;i++){
sum+=nums[i];
}
if(sum%2!=0) return false;
sum/=2;
int dp[numsSize][sum+1];
//初始化dp数组
for(int i=0;i<numsSize;i++){
dp[i][0]=0;
}
int i=0;
for(;i<=sum&&i<nums[0];i++){
dp[0][i]=0;
}
for(;i<=sum;i++){
dp[0][i]=nums[0];
}
for(i=1;i<numsSize;i++){
for(int j=1;j<=sum;j++){
if(j-nums[i]>=0){
dp[i][j]=fmax(dp[i-1][j],dp[i-1][j-nums[i]]+nums[i]);
}else{
dp[i][j]=dp[i-1][j];
}
if(dp[i][j]==sum){
return true;
}
}
}
return false;
}
一维数组(没理解)
滚动数组,二维数组的优化
//滚动数组
bool canPartition(int* nums, int numsSize){
if(numsSize==1) return false;
int sum=0;
for(int i=0;i<numsSize;i++){
sum+=nums[i];
}
if(sum%2!=0) return false;
sum/=2;
int dp[sum+1];
memset(dp,0,sizeof(int)*(sum+1));
for(int i=0;i<numsSize;i++){
for(int j=sum;j>=nums[i];j--){
dp[j]=fmax(dp[j],dp[j-nums[i]]+nums[i]);
}
}
return dp[sum]==sum;
}