Welcome to Subscribe On Youtube

494. Target Sum

Description

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

 

Constraints:

  • 1 <= nums.length <= 20
  • 0 <= nums[i] <= 1000
  • 0 <= sum(nums[i]) <= 1000
  • -1000 <= target <= 1000

Solutions

Solution 1

Dynamic programming.

It is similar to the 0-1 Knapsack problem, except that the index may appear negative, which requires special handling.

Solution 2: Dynamic Programming (Space Optimization)

We can observe that in the state transition equation of Solution 1, the value of $f[i][j]$ is only related to $f[i - 1][j]$ and $f[i - 1][j - \textit{nums}[i - 1]]$. Therefore, we can eliminate the first dimension of the space and use only a one-dimensional array.

The time complexity is $O(m \times n)$, and the space complexity is $O(n)$.

  • class Solution {
        public int findTargetSumWays(int[] nums, int target) {
            int s = 0;
            for (int v : nums) {
                s += v;
            }
            if (s < target || (s - target) % 2 != 0) {
                return 0;
            }
            int n = (s - target) / 2;
            int[] dp = new int[n + 1];
            dp[0] = 1;
            for (int v : nums) {
                for (int j = n; j >= v; --j) {
                    dp[j] += dp[j - v];
                }
            }
            return dp[n];
        }
    }
    
    
    // Solution 2
    class Solution {
        public int findTargetSumWays(int[] nums, int target) {
            int s = Arrays.stream(nums).sum();
            if (s < target || (s - target) % 2 != 0) {
                return 0;
            }
            int n = (s - target) / 2;
            int[] f = new int[n + 1];
            f[0] = 1;
            for (int num : nums) {
                for (int j = n; j >= num; --j) {
                    f[j] += f[j - num];
                }
            }
            return f[n];
        }
    }
    
    
  • class Solution {
    public:
        int findTargetSumWays(vector<int>& nums, int target) {
            int s = accumulate(nums.begin(), nums.end(), 0);
            if (s < target || (s - target) % 2 != 0) return 0;
            int n = (s - target) / 2;
            vector<int> dp(n + 1);
            dp[0] = 1;
            for (int& v : nums)
                for (int j = n; j >= v; --j)
                    dp[j] += dp[j - v];
            return dp[n];
        }
    };
    
    
    // Solution 2
    class Solution {
    public:
        int findTargetSumWays(vector<int>& nums, int target) {
            int s = accumulate(nums.begin(), nums.end(), 0);
            if (s < target || (s - target) % 2) {
                return 0;
            }
            int n = (s - target) / 2;
            int f[n + 1];
            memset(f, 0, sizeof(f));
            f[0] = 1;
            for (int x : nums) {
                for (int j = n; j >= x; --j) {
                    f[j] += f[j - x];
                }
            }
            return f[n];
        }
    };
    
    
  • class Solution:
        def findTargetSumWays(self, nums: List[int], target: int) -> int:
            s = sum(nums)
            if s < target or (s - target) % 2 != 0:
                return 0
            n = (s - target) // 2
            dp = [0] * (n + 1)
            dp[0] = 1
            for v in nums:
                for j in range(n, v - 1, -1):
                    dp[j] += dp[j - v]
            return dp[-1]
    
    
    # Solution 2
    class Solution:
        def findTargetSumWays(self, nums: List[int], target: int) -> int:
            s = sum(nums)
            if s < target or (s - target) % 2:
                return 0
            n = (s - target) // 2
            f = [0] * (n + 1)
            f[0] = 1
            for x in nums:
                for j in range(n, x - 1, -1):
                    f[j] += f[j - x]
            return f[n]
    
    
  • func findTargetSumWays(nums []int, target int) int {
    	s := 0
    	for _, v := range nums {
    		s += v
    	}
    	if s < target || (s-target)%2 != 0 {
    		return 0
    	}
    	n := (s - target) / 2
    	dp := make([]int, n+1)
    	dp[0] = 1
    	for _, v := range nums {
    		for j := n; j >= v; j-- {
    			dp[j] += dp[j-v]
    		}
    	}
    	return dp[n]
    }
    
    
    // Solution 2
    func findTargetSumWays(nums []int, target int) int {
    	s := 0
    	for _, x := range nums {
    		s += x
    	}
    	if s < target || (s-target)%2 != 0 {
    		return 0
    	}
    	n := (s - target) / 2
    	f := make([]int, n+1)
    	f[0] = 1
    	for _, x := range nums {
    		for j := n; j >= x; j-- {
    			f[j] += f[j-x]
    		}
    	}
    	return f[n]
    }
    
    
  • /**
     * @param {number[]} nums
     * @param {number} target
     * @return {number}
     */
    var findTargetSumWays = function (nums, target) {
        let s = 0;
        for (let v of nums) {
            s += v;
        }
        if (s < target || (s - target) % 2 != 0) {
            return 0;
        }
        const m = nums.length;
        const n = (s - target) / 2;
        let dp = new Array(n + 1).fill(0);
        dp[0] = 1;
        for (let i = 1; i <= m; ++i) {
            for (let j = n; j >= nums[i - 1]; --j) {
                dp[j] += dp[j - nums[i - 1]];
            }
        }
        return dp[n];
    };
    
    
    // Solution 2
    /**
     * @param {number[]} nums
     * @param {number} target
     * @return {number}
     */
    var findTargetSumWays = function (nums, target) {
        const s = nums.reduce((a, b) => a + b, 0);
        if (s < target || (s - target) % 2) {
            return 0;
        }
        const n = (s - target) / 2;
        const f = Array(n + 1).fill(0);
        f[0] = 1;
        for (const x of nums) {
            for (let j = n; j >= x; j--) {
                f[j] += f[j - x];
            }
        }
        return f[n];
    };
    
    
  • impl Solution {
        #[allow(dead_code)]
        pub fn find_target_sum_ways(nums: Vec<i32>, target: i32) -> i32 {
            let mut sum = 0;
            for e in &nums {
                sum += *e;
            }
    
            // -x + (sum - x) = target <-> -2 * x + sum = target <-> 2 * x = sum - target
            if sum < target || (sum - target) % 2 != 0 {
                // There is no way to get any expression in this case
                return 0;
            }
            let n = nums.len();
            let m = (sum - target) / 2;
    
            let mut dp: Vec<Vec<i32>> = vec![vec![0; m as usize + 1]; n + 1];
    
            // Initialize the dp vector
            dp[0][0] = 1;
    
            // Begin the actual dp phase
            for i in 1..=n {
                for j in 0..=m as usize {
                    // nums[i - 1] is not included
                    dp[i][j] = dp[i - 1][j];
                    if nums[i - 1] <= (j as i32) {
                        // nums[i - 1] is included
                        dp[i][j] += dp[i - 1][j - (nums[i - 1] as usize)];
                    }
                }
            }
    
            dp[n][m as usize]
        }
    }
    
    
    // Solution 2
    impl Solution {
        pub fn find_target_sum_ways(nums: Vec<i32>, target: i32) -> i32 {
            let s: i32 = nums.iter().sum();
            if s < target || (s - target) % 2 != 0 {
                return 0;
            }
            let n = ((s - target) / 2) as usize;
            let mut f = vec![0; n + 1];
            f[0] = 1;
            for x in nums {
                for j in (x as usize..=n).rev() {
                    f[j] += f[j - x as usize];
                }
            }
            f[n]
        }
    }
    
    
  • function findTargetSumWays(nums: number[], target: number): number {
        const s = nums.reduce((a, b) => a + b, 0);
        if (s < target || (s - target) % 2) {
            return 0;
        }
        const [m, n] = [nums.length, ((s - target) / 2) | 0];
        const f: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
        f[0][0] = 1;
        for (let i = 1; i <= m; i++) {
            for (let j = 0; j <= n; j++) {
                f[i][j] = f[i - 1][j];
                if (j >= nums[i - 1]) {
                    f[i][j] += f[i - 1][j - nums[i - 1]];
                }
            }
        }
        return f[m][n];
    }
    
    
    // Solution 2
    function findTargetSumWays(nums: number[], target: number): number {
        const s = nums.reduce((a, b) => a + b, 0);
        if (s < target || (s - target) % 2) {
            return 0;
        }
        const n = ((s - target) / 2) | 0;
        const f = Array(n + 1).fill(0);
        f[0] = 1;
        for (const x of nums) {
            for (let j = n; j >= x; j--) {
                f[j] += f[j - x];
            }
        }
        return f[n];
    }
    
    

All Problems

All Solutions