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.
Constraints:
- 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.
class Solution { int res = 0; public int findTargetSumWays(int[] nums, int S) { if(nums.length == 0) return 0; dfs(nums, S, 0, 0); return res; } public void dfs(int[] nums, int S, int pos, int cur){ if(pos == nums.length) { if(cur == S) res++; return; } dfs(nums, S, pos + 1, cur + nums[pos]); dfs(nums, S, pos + 1, cur - nums[pos]); } }
1. dfs, 每一步都可以加减,所以从cur0开始,每次dfs都可以±。
显然 还有更快的方法
public int findTargetSumWays(int[] nums, int S) { int sum = 0; for(int n: nums){ sum += n; } if (S < -sum || S > sum) { return 0;} int[][] dp = new int[nums.length + 1][ 2 * sum + 1]; dp[0][0 + sum] = 1; // 0 + sum means 0, 0 means -sum, check below graph for(int i = 1; i <= nums.length; i++){ for(int j = 0; j < 2 * sum + 1; j++){ if(j + nums[i - 1] < 2 * sum + 1) dp[i][j] += dp[i - 1][j + nums[i - 1]]; if(j - nums[i - 1] >= 0) dp[i][j] += dp[i - 1][j - nums[i - 1]]; } } return dp[nums.length][sum + S]; }
背包法,普通0/1背包是选或不选,这个是选它或者选它的负数,所以dp [ i ][ j ] = dp[i-1][j-nums[i-1]] + dp[i-1][j + nums [ i - 1];
dp[ i ][ j ]意思是:为了达到sum j,使用了前i个元素,所以上面的转移方程显然(个鬼)
因为j的范围是 -sum ---- 0 ----sum,所以我们默认dp[ 0 ][ sum]相当于起点0,所以dp[ 0 ][ 0 ] 就代表-sum,dp 【i】【sum+S】就是我们所要求的。
总结:
1. we can use DFS, if we reach the end of the array and the current number == target, we count it as a valid one, then all we need to do is recursively call dfs method to continue two operations ( plus and minus)
2. This is a 0/1 knapsack question, normally we can choose or not choose the current value, but in this question we can choose the positive value and negative value, which is pretty same
so we initiate a dp array with dimension of dp[nums.length+1][2 * sum + 1], sum is the sum of nums array. The reason we do this is our range of knapsack volume is -sum to sum ( the bound of we can use this array).
Then dp [ i ][ j ] = dp[i-1][j-nums[i-1]] + dp[i-1][j + nums [ i - 1]; dp means the number of ways for first i-th element to reach a sum j.