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:
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.
解题思路
这道题使用动态规划加哈希表解决。每添加一个加数(或减数),可以看作是在前面运算的结果集中加上(或减去)当前数字,那么得到的新结果的方法数就是结果集能得到此结果的所有元素对应的方法数的和。算法步骤如下:
1、rec 哈希表记录出现过的运算结果的次数
2、每一次从 nums 数组中取出一个数时,都与 rec 中记录的所有结果做一次 “+” 和 “-” 的运算,得到新的运算结果 res。
3、假如当前的新运算结果不存在于 rec ,那么将其作为元素添加到 rec 中;否则,rec[res] 加上 nums[i] 所记录的值
4、nums 数组遍历完成后,rec[S] 即为所求。
语句 ptr->second == 0? 1 : ptr->second; 是为了处理如 [0,0,0,0,0,1] 1 这类输入
C++代码
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
map<int, int> rec;
rec[0] = 0;
for(int i = 0; i < nums.size(); i++) {
map<int, int> rec1;
for(map<int, int>::iterator ptr = rec.begin(); ptr != rec.end(); ptr++) {
int n = ptr->first + nums[i], m = ptr->first - nums[i];
if(rec1.find(n) == rec1.end()) {
rec1[n] = ptr->second == 0? 1 : ptr->second;
}
else {
rec1[n] += ptr->second == 0? 1 : ptr->second;
}
if(rec1.find(m) == rec1.end()) {
rec1[m] = ptr->second == 0? 1 : ptr->second;
}
else {
rec1[m] += ptr->second == 0? 1 : ptr->second;
}
}
rec = rec1;
}
return rec[S];
}
};