1. 程式人生 > >leetcode -- 494. Target Sum【數學轉化 + 動態規劃】

leetcode -- 494. Target Sum【數學轉化 + 動態規劃】

題目

You are given a list of non-negative integers, a1, a2, ..., an, and a target, S. Now you have 2 symbols+ and-. For each integer, you should choose one from+ and- as its new symbol.

Find out how many ways to assign symbols to make sum of integers equal to target S.

Example 1:

Input: nums is [1, 1, 1, 1, 1], S is 3. 
Output:
5 Explanation: -1+1+1+1+1 = 3 +1-1+1+1+1 = 3 +1+1-1+1+1 = 3 +1+1+1-1+1 = 3 +1+1+1+1-1 = 3 There are 5 ways to assign symbols to make the sum of nums be target 3.

Note:

  1. The length of the given array is positive and will not exceed 20.
  2. The sum of elements in the given array will not exceed 1000.
  3. Your output answer is guaranteed to be fitted in a 32-bit integer.

題意

給定一個非負的整數陣列,a1,a2,...,an ,以及一個目標值S。現在你又兩個符號 + 和 - 。對於每一個整數,你需要從 + 或者 - 中選擇一個符號。

找出有多少種符號分配方式使得整數的和等於目標S。

分析及解答

  • 與數學的關係 】作者首先用數學公式將問題表述出來,根據正,負劃分成了兩個集合。然後考慮 target 與 兩個集合之間構成的約束的關係。然後作者使用數學技巧,將其轉化為2 * sum(P) = target + sum(nums),這說明原問題變成了,只和正數的和目標值target,所有數字的和sums相關的問題。
  • 分析數學公式 】在數學公式中,target是常量。 進一步轉化得到sum(P) = (target + sum(nums)) / 2
    sum(nums)也是容易計算的。這個公式就避免了對於sum(P)的計算。

The recursive solution is very slow, because its runtime is exponential

The original problem statement is equivalent to:
Find a subset of nums that need to be positive, and the rest of them negative, such that the sum is equal totarget

Let P be the positive subset and N be the negative subset
For example:
Given nums = [1, 2, 3, 4, 5] and target = 3 then one possible solution is+1-2+3-4+5 = 3
Here positive subset is P = [1, 3, 5] and negative subset isN = [2, 4]

Then let's see how this can be converted to a subset sum problem:

                  sum(P) - sum(N) = target
sum(P) + sum(N) + sum(P) - sum(N) = target + sum(P) + sum(N)
                       2 * sum(P) = target + sum(nums)

So the original problem has been converted to a subset sum problem as follows:
Find a subset P of nums such that sum(P) = (target + sum(nums)) / 2

Note that the above formula has proved thattarget + sum(nums) must be even
We can use that fact to quickly identify inputs that do not have a solution (Thanks to@BrunoDeNadaiSarnaglia for the suggestion)
For detailed explanation on how to solve subset sum problem, you may refer to Partition Equal Subset Sum

Here is Java solution (15 ms)

    public int findTargetSumWays(int[] nums, int s) {
        int sum = 0;
        for (int n : nums)
            sum += n;
        return sum < s || (s + sum) % 2 > 0 ? 0 : subsetSum(nums, (s + sum) >>> 1); 
    }   

    public int subsetSum(int[] nums, int s) {
        int[] dp = new int[s + 1]; 
        dp[0] = 1;
        for (int n : nums)
            for (int i = s; i >= n; i--)
                dp[i] += dp[i - n]; 
        return dp[s];
    }