494. Target-Sum

difficulty: Medium

section pre{ background-color: #eee; border: 1px solid #ddd; padding:10px; border-radius: 5px; }

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.

Constraints:

  • The length of the given array is positive and will not exceed 20.

  • The sum of elements in the given array will not exceed 1000.

  • Your output answer is guaranteed to be fitted in a 32-bit integer.

Method One

class Solution {
    public int findTargetSumWays(int[] nums, int S) {
        int maxAbsSum = 0;
        for(int n : nums){
            maxAbsSum += n; // 
        }
        if( Math.abs(S) > maxAbsSum ){
            return 0;
        }
        /** 由于输入不会超过 1000 所以我们可以只用一个 dp 数组 如果真的面试此题,需要沟通这个输入
         这是个 0/1 Knapsack Problem. 
         For each number in the array, we could either choose to add the number to
         a current sum or minus the number.
         Thus for a specific sum, we are able to receive two contributions from the
         previous sub-problems.
         Let me write down the state-transition equation here:
         dp[i][ curSum ] = dp[ i - 1 ][ curSum - nums[i - 1] ] + dp[ i - 1 ][ curSum - nums[i + 1] ];
         这个问题,由于我们始终需要选择所有的数,所以我们不需要 2D 数组,只需要两个 1D 就行。
         因为之所以我们有这个 i 在这里,是因为0/1 knapsack 问题本来是决定要不要取这个数,这里我们变成了正负号的取舍。
        */
        // int[][] dp = new int[nums.length + 1][ 2*maxAbsSum + 1];
        // dp[0][maxAbsSum] = 1;
        // for(int i = 1; i <= nums.length; i++){
        //     for(int j = -maxAbsSum; j <= maxAbsSum; j++ ){
        //         int index = j + maxAbsSum;
        //         if( index - nums[i - 1] >= 0 ){
        //             dp[i][index] += dp[i - 1][ index - nums[i - 1] ];
        //         }
        //         if( index + nums[i - 1] <= 2*maxAbsSum){
        //             dp[i][index] += dp[i - 1][ index + nums[i - 1] ];
        //         }
        //         // dp[i][index] = dp[i - 1][ index - nums[i - 1] ] + dp[ i - 1 ][ index + nums[i - 1] ]
        //     }
        // }
        // return dp[nums.length][S + maxAbsSum];

        // 这是1D的答案
        int[] dp = new int[ 2*maxAbsSum + 1];
        dp[maxAbsSum] = 1;
        for(int i = 0; i < nums.length; i++){
            int[] next = new int[ 2*maxAbsSum + 1];
            for(int j = -maxAbsSum; j <= maxAbsSum; j++ ){
                int index = j + maxAbsSum;
                if( index - nums[i] >= 0 ){
                    next[index] += dp[ index - nums[i] ];
                }
                if( index + nums[i] <= 2*maxAbsSum){
                    next[index] += dp[ index + nums[i] ];
                }
            }
            dp = next;
        }
        return dp[S + maxAbsSum];
    }
}​

Last updated

Was this helpful?