給定一個只包含正整數的非空數組。是否可以將這個數組分割成兩個子集,使得兩個子集的元素和相等。
注意:每個數組中的元素不會超過 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;
}
}
}