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:
- The length of the given array is positive and will not exceed 20.
- The sum of elements in the given array will not exceed 1000.
- Your output answer is guaranteed to be fitted in a 32-bit integer.
使用了两个Map进行辅助
public class Solution {
public int findTargetSumWays(int[] nums, int S) {
if(nums.length==0||nums==null) return 0;
Map<Integer, Integer> ans = new HashMap<>();
Map<Integer, Integer> temp = new HashMap<>();
ans.put(nums[0], 1);
ans.put(-nums[0], ans.getOrDefault(-nums[0], 0) + 1);
for(int i=1; i<nums.length; i++){
for(int k : ans.keySet()){
temp.put(k+nums[i], temp.getOrDefault(k+nums[i], 0) + ans.get(k));
temp.put(k-nums[i], temp.getOrDefault(k-nums[i], 0) + ans.get(k));
}
ans = temp;
temp = new HashMap<>();
}
return ans.getOrDefault(S, 0);
}
}
别人的dp方法,分析了该问题的子问题,转化成了取数的形式
The recursive solution is very slow, because its runtime is exponential
The original problem statement is equivalent to:
Find a subset of nums
that need to be positive, and the rest of them negative, such that the sum is equal to target
Let P
be the positive subset and N
be the negative subset
For example:
Given nums = [1, 2, 3, 4, 5]
and target = 3
then one possible solution is +1-2+3-4+5 = 3
Here positive subset is P = [1, 3, 5]
and negative subset is N = [2, 4]
Then let's see how this can be converted to a subset sum problem:
sum(P) - sum(N) = target
sum(P) + sum(N) + sum(P) - sum(N) = target + sum(P) + sum(N)
2 * sum(P) = target + sum(nums)
So the original problem has been converted to a subset sum problem as follows:
Find a subset P
of nums
such that sum(P) = (target + sum(nums)) / 2
Note that the above formula has proved that target + sum(nums)
must be even
We can use that fact to quickly identify inputs that do not have a solution
public int findTargetSumWays(int[] nums, int s) {
int sum = 0;
for (int n : nums)
sum += n;
return sum < s || (s + sum) % 2 > 0 ? 0 : subsetSum(nums, (s + sum) >>> 1);
}
public int subsetSum(int[] nums, int s) {
int[] dp = new int[s + 1];
dp[0] = 1;
for (int n : nums)
for (int i = s; i >= n; i--)
dp[i] += dp[i - n];
return dp[s];
}