Problem
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'+'
before2
and a'-'
before1
and concatenate them to build the expression"+2-1"
.
Return the number of different expressions that you can build, which evaluates to target
.
Examples
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
Solution
Method 1 - DFS
This solution involves exploring every possible combination of ‘+’ and ‘-’ for each element in the nums
array and calculating the number of ways to get the target sum.
Approach
- For each number in the
nums
array, we have two choices: add the number to the current sum or subtract the number from the current sum. - Recursively explore both choices for each number and keep track of the current sum.
- If we reach the end of the array and the current sum equals the target, we count that as a valid expression.
This is how the recursive tree will look:
--- title: Recursion tree for nums = [1,1,1,1,1] and target = 3 --- graph TD Start([Start]) --> A1["+1"] & B1["-1"] A1 --> A2["+1"] & B2["-1"] B1 --> C2["+1"] & D2["-1"] A2 --> A3["+1"] & B3["-1"] B2 --> Dd1["..."] C2 --> Dd2["..."] D2 --> Dd3["..."] A3 --> A4["+1"] & B4["-1"] B3 --> Dd4["..."] A4 --> A5["+1"] & B5["-1"] B4 --> C5["+1"] & D5["-1"] classDef validExp fill:#9f6,stroke:#333,stroke-width:2px; B5:::validExp C5:::validExp
Code
Java
class Solution {
public int findTargetSumWays(int[] nums, int target) {
return calculate(nums, target, 0, 0);
}
private int calculate(int[] nums, int target, int index, int currentSum) {
if (index == nums.length) {
return currentSum == target ? 1 : 0;
}
int add = calculate(nums, target, index + 1, currentSum + nums[index]);
int subtract = calculate(nums, target, index + 1, currentSum - nums[index]);
return add + subtract;
}
}
Python
class Solution:
def findTargetSumWays(self, nums: List[int], target: int) -> int:
def calculate(index: int, current_sum: int) -> int:
if index == len(nums):
return 1 if current_sum == target else 0
add = calculate(index + 1, current_sum + nums[index])
subtract = calculate(index + 1, current_sum - nums[index])
return add + subtract
return calculate(0, 0)
Complexity
- ⏰ Time complexity:
O(2^n)
, wheren
is the number of elements innums
because at each element, we branch into two recursive calls. - 🧺 Space complexity:
O(n)
, due to the depth of the recursion tree.
Method 2 - Top Down DP with memoization
- We use a dictionary to store the results of subproblems, where the key is a tuple
(index, current_sum)
and the value is the number of ways to get thetarget
sum starting from that index with the given current sum. - When we encounter a subproblem result that we have already computed previously, we return the stored result instead of recalculating it.
Video explanation
Here is the video explaining this method in detail. Please check it out:
Code
Java
class Solution {
private Map<String, Integer> memo = new HashMap<>();
public int findTargetSumWays(int[] nums, int target) {
return calculate(nums, target, 0, 0);
}
private int calculate(int[] nums, int target, int index, int currentSum) {
if (index == nums.length) {
return currentSum == target ? 1 : 0;
}
String key = index + "," + currentSum;
if (memo.containsKey(key)) {
return memo.get(key);
}
int add = calculate(nums, target, index + 1, currentSum + nums[index]);
int subtract = calculate(nums, target, index + 1, currentSum - nums[index]);
int result = add + subtract;
memo.put(key, result);
return result;
}
}
Python
class Solution:
def __init__(self):
self.memo: Dict[Tuple[int, int], int] = {}
def findTargetSumWays(self, nums: List[int], target: int) -> int:
def calculate(index: int, current_sum: int) -> int:
if index == len(nums):
return 1 if current_sum == target else 0
if (index, current_sum) in self.memo:
return self.memo[(index, current_sum)]
add = calculate(index + 1, current_sum + nums[index])
subtract = calculate(index + 1, current_sum - nums[index])
self.memo[(index, current_sum)] = add + subtract
return self.memo[(index, current_sum)]
return calculate(0, 0)
Complexity
- ⏰ Time complexity:
O(n * 2*sum)
, wheren
is the number of elements innums
andsum
is the sum of the absolute values ofnums
. - 🧺 Space complexity:
O(n * 2*sum)
, due to the space required to store the memoization table.
Method 3 - Top Down DP
In the bottom-up approach, we use a DP table where dp[i][j]
represents the number of ways to get sum j
using the first i
elements of nums
. We use one table to store the results and iterate through the array to fill up this table iteratively.
- Initialise a DP array of size
(n+1) x (2*sum + 1)
wheresum
is the sum of the absolute values ofnums
. - Set the base case:
dp[0][sum] = 1
, which corresponds to achieving a zero sum with zero elements. - Populate the DP table: for each element, update the DP table for both addition and subtraction.
- Return the value stored in
dp[n][target + sum]
.
Code
Java
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for (int num : nums) {
sum += Math.abs(num);
}
if (target > sum || target < -sum) {
return 0;
}
int[][] dp = new int[nums.length + 1][2 * sum + 1];
dp[0][sum] = 1;
for (int i = 1; i <= nums.length; i++) {
for (int j = 0; j <= 2 * sum; j++) {
if (dp[i-1][j] != 0) {
if (j + nums[i - 1] <= 2 * sum) {
dp[i][j + nums[i - 1]] += dp[i-1][j];
}
if (j - nums[i - 1] >= 0) {
dp[i][j - nums[i - 1]] += dp[i-1][j];
}
}
}
}
return dp[nums.length][target + sum];
}
}
Python
class Solution:
def findTargetSumWays(self, nums: List[int], target: int) -> int:
total_sum = sum(abs(num) for num in nums)
if target > total_sum or target < -total_sum:
return 0
dp = [[0] * (2 * total_sum + 1) for _ in range(len(nums) + 1)]
dp[0][total_sum] = 1
for i in range(1, len(nums) + 1):
for j in range(2 * total_sum + 1):
if dp[i-1][j] != 0:
if j + nums[i - 1] <= 2 * total_sum:
dp[i][j + nums[i - 1]] += dp[i-1][j]
if j - nums[i - 1] >= 0:
dp[i][j - nums[i - 1]] += dp[i-1][j]
return dp[len(nums)][target + total_sum]
Complexity
- ⏰ Time complexity:
O(n * 2*sum)
, wheren
is the number of elements innums
andsum
is the sum of the absolute values ofnums
. - 🧺 Space complexity:
O(n * 2*sum)