You are given an array of integers nums and an integer target.
For each number in the array, you can choose to either add or subtract it to a total sum.
nums = [1, 2], one possible sum would be "+1-2=-1".If nums=[1,1], there are two different ways to sum the input numbers to get a sum of 0: "+1-1" and "-1+1".
Return the number of different ways that you can build the expression such that the total sum equals target.
Example 1:
Input: nums = [2,2,2], target = 2
Output: 3Explanation: There are 3 different ways to sum the input numbers to get a sum of 2.+2 +2 -2 = 2+2 -2 +2 = 2-2 +2 +2 = 2
Constraints:
1 <= nums.length <= 200 <= nums[i] <= 1000-1000 <= target <= 1000
You should aim for a solution as good or better than O(n * m) time and O(n * m) space, where n is the size of the input array and m is the sum of all the elements in the array.
Try to think in terms of recursion and visualize it as a decision tree, where we have two choices at each recursion step: assigning a positive or negative sign.
We recursively iterate through the array using index i, tracking the current sum along the recursive path. Each step branches into two paths, and we sum the number of ways to reach the target. If the index i goes out of bounds, we return 1 if the current sum equals the target; otherwise, we return 0.
This approach is exponential. We can use memoization to cache recursive call results and avoid redundant calculations. A hash map or a 2D array with modifications can be used for caching. If using a 2D array, the dimensions can be (n * (2m + 1)), where n is the array size and m represents the sum of the array elements.
This problem asks us to count how many different ways we can assign a + or - sign to each number so that the final sum equals the target.
At every index, we have two independent choices:
Using recursion, we try all possible sign assignments.
The recursive function represents:
"How many ways can we reach the target starting from index i with the current sum total?"
When all numbers are processed, we simply check whether the accumulated sum equals the target.
backtrack(i, total):i is the current index in the arraytotal is the sum formed so fari reaches the end of the array:1 if total equals the target0totaltotal0 with an initial sum of 0This problem asks us to count the number of ways to assign a + or - sign to each number so that the final sum equals the target.
The recursive solution tries all possible sign combinations, but many subproblems repeat. To avoid recomputing the same states, we use top-down dynamic programming (memoization).
Each state is uniquely defined by:
itotalThe recursive function answers the question:
"How many ways can we reach the target starting from index i with the current sum total?"
By caching results for each state, we significantly improve efficiency.
dp where:(i, total)backtrack(i, total):i represents the current index in the arraytotal represents the sum formed so fari reaches the end of the array:1 if total equals the target0(i, total) is already in dp:totaltotaldp[(i, total)]0 with an initial sum of 0class Solution:
def findTargetSumWays(self, nums: List[int], target: int) -> int:
dp = {} # (index, total) -> # of ways
def backtrack(i, total):
if i == len(nums):
return 1 if total == target else 0
if (i, total) in dp:
return dp[(i, total)]
dp[(i, total)] = (backtrack(i + 1, total + nums[i]) +
backtrack(i + 1, total - nums[i]))
return dp[(i, total)]
return backtrack(0, 0)Where is the length of the array and is the sum of all the elements in the array.
We need to count how many ways we can assign a + or - sign to each number so that the final sum equals the target.
Instead of using recursion, we can solve this using bottom-up dynamic programming, where we build solutions step by step as we process each number.
At each position, we keep track of:
As we move forward, each existing sum can branch into two new sums by adding or subtracting the current number.
n be the length of the input array.dp of size n + 1:dp[i] stores how many ways each sum can be formed using the first i numbersdp[0][0] = 1 since there is exactly one way to form sum 0 using no numbers0 to n - 1:(sum, count) in dp[i]:dp[i + 1][sum + nums[i]]dp[i + 1][sum - nums[i]]dp[n][target] gives the number of valid waysdp[n][target]class Solution:
def findTargetSumWays(self, nums: List[int], target: int) -> int:
n = len(nums)
dp = [defaultdict(int) for _ in range(n + 1)]
dp[0][0] = 1
for i in range(n):
for total, count in dp[i].items():
dp[i + 1][total + nums[i]] += count
dp[i + 1][total - nums[i]] += count
return dp[n][target]Where is the length of the array and is the sum of all the elements in the array.
We want to count the number of ways to assign + and - signs to the numbers so that their final sum equals the target.
In the bottom-up DP approach, we used a separate data structure for each index. However, at each step, the new states depend only on the previous step, not on all earlier steps.
This means we can reuse a single data structure to keep track of all possible sums and how many ways each sum can be formed, updating it as we process each number.
dp where:dp[0] = 1 since there is exactly one way to reach sum 0 before using any numbersnext_dp to store updated sums(total, count) in dp:next_dp[total + num]next_dp[total - num]dp with next_dp after processing the current numberdp[target] gives the number of valid waysdp[target]class Solution:
def findTargetSumWays(self, nums: List[int], target: int) -> int:
dp = defaultdict(int)
dp[0] = 1
for num in nums:
next_dp = defaultdict(int)
for total, count in dp.items():
next_dp[total + num] += count
next_dp[total - num] += count
dp = next_dp
return dp[target]Where is the length of the array and is the sum of all the elements in the array.