给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意:每个数组中的元素不会超过 100
示例 1:
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
示例 2:
输入: [1, 2, 3, 5]
输出: false
解释: 数组不能分割成两个元素和相等的子集.
数组的大小不会超过 200.
这道题主要是如何将问题转化为01背包。首先如果数组中所有数据的加和(定义为sum)是奇数,一定是false,否则还要看从选区数组中部分数据能不能放满sum/2 ,如果可以则为true否则为false。
public static boolean canPartition(int[] nums) {
int len = nums.length;
int sum = 0;
for(int i = 0;i < len;i++){
sum += nums[i];
}
if(sum % 2==1){
return false;
} else {
sum >>= 1;
int[][] dp = new int[len+1][sum+1];
for(int i = 0;i <=len;i++){
for(int j = 0;j <=sum;j++){
dp[i][j] = -99999;
}
}
for(int i = 0;i < len ;i++){
dp[i][0] = 0;
}
System.out.println(sum);
for(int i = 1;i <= len;i++) {
for(int j = 0;j <= sum ;j++) {
//for(int j = sum;j >=0 ;j--){ 双重循环的时候从0到sum不能反了
if(j >= nums[i-1]) {
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-nums[i-1]] + nums[i-1]);
if( dp[i][j] < 0 ) {
dp[i][j] = -99999;
}
} else {
dp[i][j] = dp[i-1][j];
}
System.out.print(dp[i][j] +" ");
}
System.out.println();
}
if(dp[len][sum] == sum) {
return true;
} else {
return false;
}
}
}
优化
空间优化:(优化为一维数组)
public static boolean canPartition(int[] nums) {
int len = nums.length;
int sum = 0;
for(int i = 0;i < len;i++){
sum += nums[i];
}
if(sum % 2==1){
return false;
} else {
sum >>= 1;
int[] dp = new int[sum+1];
for(int j = 1;j <=sum;j++){
dp[j] = -99999;
}
System.out.println(sum);
for(int i = 1;i <= len;i++) {
for(int j = sum;j >= 0 ;j--) {
//for(int j = sum;j >=0 ;j--){ 双重循环的时候从0到sum不能反了
if(j >= nums[i-1]) {
dp[j] = Math.max(dp[j],dp[j-nums[i-1]] + nums[i-1]);
if( dp[j] < 0 ) {
dp[j] = -99999;
}
}
}
}
if(dp[sum] == sum) {
return true;
} else {
return false;
}
}
}