Skip to content

494. Target Sum Medium ​

You are given an integer array nums and an integer target.

You want to build an expression out of nums by adding one of the symbols '+' and '-' before each integer in nums and then concatenate all the integers.

For example, if nums = [2, 1], you can add a '+' before 2 and a '-' before 1 and concatenate them to build the expression "+2-1".

Return the number of different expressions that you can build, which evaluates to target.

Example 1:
Input: nums = [1,1,1,1,1], target = 3
Output: 5
Explanation: There are 5 ways to assign symbols to make the sum of nums be target 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
+1 + 1 + 1 + 1 - 1 = 3

Example 2:
Input: nums = [1], target = 1
Output: 1

Approach ​

Input: A non-negative integer array nums, an integer target.

Output: Each number can be preceded by + or -, return the number of different expressions that evaluate to target.

This problem belongs to 0-1 Knapsack + Counting DP problems.

This problem has multiple solutions:

  1. Memoized Recursion (DFS + Cache)
  2. 2D DP Table Method
  3. 1D DP (Rolling Array Optimization)

Core Transformation (0-1 Knapsack + Counting DP) ​

Suppose:

  • The sum of all numbers is s
  • The sum of all numbers preceded by + is p

Then the sum of all numbers preceded by - is s - p. The total result required by the problem is p - (s - p) = target.

Simplifying gives:

text
2p - s = target  =>  p = (s + target) / 2

In other words, the problem transforms into:

Pick some numbers from the array such that their sum is (s + target) // 2. How many ways are there to pick?

This is exactly a typical 0-1 Knapsack problem (each number can only be picked once), and since we care about how many ways, it's Counting DP.

Constraint Checking: ​

  • (s + target) must be an even number (otherwise indivisible)
  • p = (s + target) / 2 must be a non-negative integer (otherwise no solution)

Solution 1: Memoized Search (Recursion + Cache) ​

Idea:

  • Definition: dfs(i, c) represents picking some elements from the first i numbers summing to c.
  • Transition Equation:
    • Do not pick current number: dfs(i - 1, c)
    • Pick current number: dfs(i - 1, c - nums[i])
  • Base Case: when i < 0, yielding 1 if c == 0 else 0.

Solution 2: 2D DP Table Method (Traditional 0-1 Knapsack) ​

Idea:

  • Definition: dp[i][j] expresses combination counts selecting from top i components scoring exactly j.
  • Initialization: dp[0][0] = 1
  • State transitions:
    • Don't add current element: dp[i][j] = dp[i - 1][j]
    • Append element recursively: dp[i][j] += dp[i - 1][j - nums[i - 1]]

Solution 3: 1D DP (Space Optimized) ​

Idea:

  • Definition: dp[c] sums valid configurations accumulating identically to c.
  • Initialization: dp[0] = 1
  • For every value x, traverse bottom up checking array components decreasingly from target down to x:
    js
    dp[c] += dp[c - x]
  • Sweeping iteratively bottom up prevents using current numbers redundantly mimicking basic 0-1 Knapsack DP syntax.

Implementation ​

Solution 1: Memoized Search (Recursion + Cache)

python
from functools import cache
from typing import List

class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        total_sum = sum(nums)

        # Generating updated total combination tracking needs to be strictly even and positive
        new_target = target + total_sum
        if new_target < 0 or new_target % 2 == 1:
            return 0

        # Transforming problem logic determining correct value accumulation sums equating roughly exact middle values
        new_target //= 2

        n = len(nums)

        # Memoization Recursion logic representing choices available picking values equating accurately target tracking subsets
        @cache
        def dfs(i: int, c: int) -> int:
            # If values exhausted verifying completion match 
            if i < 0:
                return 1 if c == 0 else 0

            # Discard skipping tracking choice logic 
            res = dfs(i - 1, c)

            # Accept choices adjusting total counts satisfying limitations accurately
            if c >= nums[i]:
                res += dfs(i - 1, c - nums[i])

            return res

        return dfs(n - 1, new_target)
javascript
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var findTargetSumWays = function(nums, target) {
    const sum = nums.reduce((acc, curr) => acc + curr, 0);

    let new_target = target + sum;

    if (new_target < 0 || new_target % 2 == 1) {
        return 0
    }

    new_target /= 2

    const cache = {};

    function dfs(i, c) {
        if (i < 0) return c == 0 ? 1 : 0;

        if (cache[`${i} + ${c}`] != null) return cache[`${i} + ${c}`];

        let res = dfs(i - 1, c);

        if (c >= nums[i]) {
            res += dfs(i - 1, c - nums[i]);
        }

        cache[`${i} + ${c}`] = res;

        return res;
    }

    return dfs(nums.length - 1, new_target);
};

Solution 2: 2D DP Table Method (Traditional 0-1 Knapsack)

python
from typing import List

class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        total = sum(nums)
        target += total  # Shift calculation resolving subsets satisfying formula accurately

        # Validate limitations satisfying accurate target configurations mathematically correctly
        if target < 0 or target % 2 == 1:
            return 0

        target //= 2  # Find combination limits effectively equating sums targeted values

        n = len(nums)
        # Tracking permutations generating paths combinations reaching constraints effectively
        f = [[0] * (target + 1) for _ in range(n + 1)]
        f[0][0] = 1  # Formulating initialization 0 choices satisfying zero sum limitations

        for i, x in enumerate(nums):
            # Evaluate combinations tracking accurately subsets generating targets successfully
            for j in range(target + 1):
                if j < x:
                    # Retain values resolving configurations unable holding elements efficiently
                    f[i + 1][j] = f[i][j]
                else:
                    # Compound combination paths selecting accurate constraints targeting formulas correctly
                    f[i + 1][j] = f[i][j] + f[i][j - x]

        return f[n][target]
javascript
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var findTargetSumWays = function(nums, target) {
    // Bottom-Up Approach
    const sum = nums.reduce((acc, curr) => acc + curr, 0);

    let new_target = target + sum;

    if (new_target < 0 || new_target % 2 == 1) {
        return 0
    }

    new_target /= 2

    const rows = nums.length + 1;
    const cols = new_target + 1;

    const f = Array.from({length: rows}, () => Array(cols).fill(0));
    f[0][0] = 1;

    for (let i = 0; i < nums.length; i++) {
        for (let j = 0; j < new_target + 1; j++) {
            if (j < nums[i]) {
                f[i + 1][j] = f[i][j];
            } else {
                f[i + 1][j] = f[i][j] + f[i][j - nums[i]];
            }
        }
    }

    return f[nums.length][new_target];
}

Solution 3: 1D DP (Space Optimized)

python
from typing import List

class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        total = sum(nums)

        target += total

        if target < 0 or target % 2 == 1:
            return 0

        target //= 2

        f = [0] * (target + 1)
        f[0] = 1

        for x in nums:
            # Sweeping iterative combinations effectively iterating backward enforcing unique usages completely constraints limits 
            for c in range(target, x - 1, -1):
                f[c] = f[c] + f[c - x]

        return f[target]
javascript
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var findTargetSumWays = function(nums, target) {
    // Rolling array optimization
    const sum = nums.reduce((acc, curr) => acc + curr, 0);

    let new_target = target + sum;

    if (new_target < 0 || new_target % 2 == 1) {
        return 0
    }

    new_target /= 2

    const f = Array(new_target + 1).fill(0);
    f[0] = 1;

    for (let i = 0; i < nums.length; i++) {
        const x = nums[i];
        for (let j = new_target; j > x - 1; j--) {
            f[j] = f[j] + f[j - nums[i]];
        }
    }

    return f[new_target];
}

Complexity Analysis ​

  • Time Complexity: O(n * target)
  • Space Complexity:
    • Memoized Recursion (DFS + Cache): O(n * target)
    • 2D DP Table Method: O(n * target)
    • 1D DP (Space Optimized): O(target)

494. Target Sum (English)

494. 目标和 (Chinese)