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.


Solution


Approach #1 Brute Force [Accepted]

Algorithm

The brute force approach is based on recursion. We need to try to put both the + and - symbols at every location in the given array and find out the assignments which lead to the required result .

For this, we make use of a recursive function calculate(nums, i, sum, S), which returns the assignments leading to the sum , starting from the index onwards, provided the sum of elements upto the element is . This function appends a + sign and a - sign both to the element at the current index and calls itself with the updated as and repectively along with the updated current index as . Whenver, we reach the end of the array, we compare the sum obtained with . If they are equal, we increment the value to be returned.

Thus, the function call calculate(nums, 0, 0, S) retuns the required no. of assignments.

Complexity Analysis

  • Time complexity : . Size of recursion tree will be . refers to the size of array.

  • Space complexity : . The depth of the recursion tree can go upto .


Approach #2 Recursion with memoization [Accepted]

Algorithm

It can be easily observed that in the last approach, a lot of redundant function calls could be made with the same value of as the current index and the same value of as the current sum, since the same values could be obtained through multiple paths in the recursion tree. In order to remove this redundancy, we make use of memoization as well to store the results which have been calculated earlier.

Thus, for every call to calculate(nums, i, sum, S), we store the result obtained in . The factor of 1000 has been added as an offset to the value to map all the s possible to positive integer range. By making use of memoization, we can prune the search space to a good extent.

Complexity Analysis

  • Time complexity : . The array of size has been filled just once. Here, refers to the range of and refers to the size of array.

  • Space complexity : . The depth of recursion tree can go upto .


Approach #3 2D Dynamic Programming [Accepted]

Algorithm

The idea behind this approach is as follows. Suppose we can find out the number of times a particular sum, say is possible upto a particular index, say , in the given array, which is given by say . Now, we can find out the number of times the sum can occur easily as . Similarly, the number of times the sum occurs is also given by .

Thus, if we know all the sums 's which are possible upto the index by using various assignments, along with the corresponding count of assignments, , leading to the same sum, we can determine all the sums possible upto the index along with the corresponding count of assignments leading to the new sums.

Based on this idea, we make use of a to determine the number of assignments which can lead to the given sum. refers to the number of assignments which can lead to a sum of upto the index. To determine the number of assignments which can lead to a sum of upto the index, we can use . Similarly, . We iterate over the array in a rowwise fashion i.e. Firstly we obtain all the sums which are possible upto a particular index along with the corresponding count of assignments and then proceed for the next element(index) in the array.

But, since the $$sum can range from -1000 to +1000, we need to add an offset of 1000 to the sum indices (column number) to map all the sums obtained to positive range only.

At the end, the value of gives us the required number of assignments. Here, refers to the number of elements in the array.

The animation below shows the way various sums are generated along with the corresponding indices. The example assumes values to lie in the range of -6 to +6 just for the purpose of illustration. This animation is inspired by @Chidong

!?!../Documents/494_Target_Sum.json:1000,563!?!

Complexity Analysis

  • Time complexity : . The entire array is travesed 2001(constant no.: ) times. refers to the size of array. refers to the range of possible.

  • Space complexity : . array of size is used.


Approach #4 1D Dynamic Programming [Accepted]:

Algorithm

If we look closely at the last solution, we can observe that for the evaluation of the current row of , only the values of the last row of are needed. Thus, we can save some space by using a 1D DP array instead of a 2-D DP array. The only difference that needs to be made is that now the same array will be updated for every row traversed.

Below code is inspired by @Chidong

Complexity Analysis

  • Time complexity : . The entire array is traversed times. refers to the size of array. refers to the range of possible.

  • Space complexity : . array of size is used.


Analysis written by: @vinod23