Given an array of non-negative integers, a1, a2, …, an, and a target number, S. Now you have two symbols + and -. For any integer in the array, you can choose a symbol from + or-and add it in front.
Returns the number of methods that can make the final array and add symbols to the target number S.
Example:
Input: nums: [1, 1, 1, 1, 1], S: 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 make the final goal sum to 3.
analysis:
For dynamic programming, the problem is transformed into a 0-1 knapsack problem, and the target S is transformed into a problem of how to load items with different volumes in the knapsack. The recurrence formula is d[j] = d[j] + d[j-nums[i] ], traverse from back to front, to ensure that each item (nums[j]) is used only once, taking {1,1,1,1,1} as an example, draw the state transition table as shown below
public:
int findTargetSumWays(vector<int>& nums, int S) {
int wayTimes = 0;
int sum = 0;
for(int i = 0; i < nums.size(); i++) sum += nums[i];
if (S > sum) return 0; // sum全为正数组成也无法找到S
// 我们假设P是正子集,N是负子集
// 例如: 假设nums = [1, 2, 3, 4, 5],target = 3,
// 一个可能的解决方案是+1-2+3-4+5 = 3 这里正子集P = [1, 3, 5]和负子集N = [2, 4]
// 满足 x - (sum - x) = S => x = (S + sum) / 2
// 推导: 假设加法的总和为x,那么减法对应的总和就是sum - x
if ((S + sum) % 2 == 1) return 0;
int bagSize = (S + sum) / 2;
vector<int> dp(bagSize + 1, 0);
dp[0] = 1;
for(int i = 0; i < nums.size(); i++){
for(int j = bagSize; j >= nums[i]; j--){
dp[j] += dp[j - nums[i]];
}
}
for(int x : dp) cout << x <<" ";
return dp[bagSize];
}