分割等和子集-01背包问题

124 阅读1分钟
// 分割等和子集-01背包问题  
// 输入:nums = [1,5,11,5]  
// 输出:true  
// 解释:数组可以分割成 [1, 5, 5] 和 [11] 。  
public static boolean canPartition(int[] nums){  
    int len=nums.length;  
    int sum=0;  
    for(int num:nums){  
        sum+=num;  
    }  
    if((sum&1)==1){  
        return false;  
    }  
    int target=sum/2;  
    boolean[][] dp=new boolean[len][target+1];  
    if(nums[0]<=target){  
        dp[0][nums[0]]=true;  
    }  
    //个数  
    for (int i = 1; i <len ; i++) {  
        //容量  
        for (int j = 0; j <=target ; j++) {  
            // 不选nums[i]  
            dp[i][j]=dp[i-1][j];  
            if(nums[i]==j){  
                dp[i][j]=true;  
                continue;  
            }  
            // nums[i]<j说明还能装 选nums[i]  
            if(nums[i]<j){  
                // 没选nums[i]恰好等于dp[i-1][j]  
                // 选num[i] 需要j-nums[i]的容量推导来  
                dp[i][j]=dp[i-1][j] || dp[i-1][j-nums[i]];  
            }  
        }  
    }  
    return dp[len-1][target];  
}  
  
public static boolean canPartitionTwo(int[] nums){  
    int len=nums.length;  
    int sum=0;  
    for (int num:  
    nums) {  
        sum+=num;  
    }  
    if((sum&1)==1){  
        return false;  
    }  
    int target=sum/2;  
    boolean[] dp=new boolean[target+1];  
    dp[0]=true;  
    if(nums[0]<=target){  
        dp[nums[0]]=true;  
    }  
    for (int i = 1; i <len ; i++) {  
        for (int j = target; nums[i] <=j ; j--) {  
            if(dp[target]){  
                return true;  
            }  
            dp[j]=dp[j]||dp[j-nums[i]];  
        }  
    }  
    return dp[target];  
}