1. 程式人生 > >Leetcode——分割等和

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;
    }
}