Leetcode——分割等和

题目描述:给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

解题思路:

  • 可以看成一个背包大小为 sum/2 的 0-1 背包问题。

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = sum(nums);
        if(sum%2!=0)
            return false;
        int w = sum / 2;
        boolean dp[] = new boolean[w+1];
        dp[0] = true;
        for(int num:nums){
            for(int j = w;j>=num;j--)
                dp[j] = dp[j]||dp[j-num];
        }
        return dp[w];
    }
    public int sum(int[] nums){
        int sum = 0;
        for(int x:nums)
            sum += x;
        return sum;
    }
}

拓展——改变一组数的正负号使得它们的和为一给定数

题目描述:给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。返回可以使最终数组和为目标数 S 的所有添加符号的方法数。

解题思路:

  • 该问题可以转换为 Subset Sum 问题,从而使用 0-1 背包的方法来求解。
  • 可以将这组数看成两部分,P 和 N,其中 P 使用正号,N 使用负号,有以下推导:

 因此只要找到一个子集,令它们都取正号,并且和等于 (target + sum(nums))/2,就证明存在解。

class Solution {
    public int findTargetSumWays(int[] nums, int S) {
        int sum = sum(nums);
        if(S>sum||(sum+S)%2!=0)
            return 0;
        int w = (sum + S)/2;
        int[] dp = new int[w+1];
        dp[0] = 1;
        for(int num:nums){
            for(int j = w;j>=num;j--)
                dp[j] = dp[j] + dp[j-num];
        }
        return dp[w];
    }
    public int sum(int[] nums){
        int sum = 0;
        for(int num:nums)
            sum += num;
        return sum;
    }
}

你可能感兴趣的:(Leetcode)