设数组的和为sum,把分割等和子集转成求数组能否凑出和为sum/2。由此题目变成了标准的01背包问题。
几个数能否出某一个数可以用动态规划来做,建立一个下面的数组:
int target = sum/2;
boolean[][] dp = new boolean[nums.length][target+1];
dp[i][j]有三种情况:
当if(j < nums[i]) dp[i][j] = dp[i-1][j];
当if(j = nums[i]) dp[i][j] = true;
当if(j > nums[i]) dp[i][j] = (dp[i-1][j] || dp[i-1][j-nums[i]]);
class Solution {
public boolean canPartition(int[] nums) {
int sum = 0;
for(int num : nums){
sum += num;
}
if(sum%2 == 1){
return false;
}
int target = sum/2;
boolean[][] dp = new boolean[nums.length][target+1];
// dp[0][nums[0]] = nums[0] <= target ? true : false;这种写法dp[0][nums[0]]会越界
if(nums[0] < target){
dp[0][nums[0]] = true;
}
for(int i = 1; i < nums.length; i++){
for(int j = 0; j <= target; j++){
dp[i][j] = dp[i-1][j];
if(nums[i] == j){
dp[i][j] = true;
continue;
}
if(j > nums[i]){
dp[i][j] = dp[i-1][j]||dp[i-1][j-nums[i]];
}
}
}
return dp[nums.length-1][target];
}
}
- 动态规划数组是一维数组
class Solution {
public boolean canPartition(int[] nums) {
int sum = 0;
for(int num : nums){
sum += num;
}
int target = sum/2;
if((sum & 1) ==1){
return false;
}
boolean[] dp = new boolean[target+1];
/*
若nums[i]<=target(即,nums[i]没有越dp的界),当j==nums[i],dp[i][j]应该是true。
~~因为dp[i][j]=dp[i-1][j]||dp[i-1][j-nums[i]],
所以dp[0] = true,即可以实现当j==nums[i],dp[i][nums[i]]=dp[i-1][nums[i]-nums[i]]dp[i][j]是true的效果。~~
*/
dp[0] = true;
if(nums[0] <= target){//if判断nums[i]有没有越dp的界限
dp[nums[0]] = true;
}
for(int i = 1; i < nums.length; i++){
for(int j=target; j >= nums[i]; j--){
if(dp[target]){
return true;
}
dp[j] = dp[j] || dp[j-nums[i]];
}
}
return dp[target];
}
}