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.
参考:here。
这道题首先想到的就是利用递归便利所有的可能:
class Solution {
private:
int help(vector<int>& nums, int start, long rem){
if(start>=nums.size()) return rem==0?1:0;
int ans1 = help(nums, start+1, rem-nums[start]);
int ans2 = help(nums, start+1, rem+nums[start]);
return ans1+ans2;
}
public:
int findTargetSumWays(vector<int>& nums, int S) {
return help(nums, 0, S);
}
};
但是一般直接这样用会超时,TLE。
然后对其进行优化,将一些已经遍历过的场景记录下来:
class Solution {
private:
vector<unordered_map<int,int>> vm;
int help(vector<int>& nums, int start, long rem) {
if (start >= nums.size()) return rem == 0 ? 1 : 0;
if (vm[start][rem]) return vm[start][rem];
int ans1 = help(nums, start + 1, rem - nums[start]);
int ans2 = help(nums, start + 1, rem + nums[start]);
return vm[start][rem] = ans1 + ans2;
}
public:
int findTargetSumWays(vector<int>& nums, int S) {
this->vm.resize(nums.size());
return help(nums, 0, S);
}
};
发现还是超时了。
最后使用动态迭代的方式,成功完成。
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
unordered_map<long,int> m;
m[0] = 1;
for(int num:nums){
unordered_map<long, int> t;
for(auto it:m){
int sum = it.first, cnt = it.second;
t[sum+num] += cnt;
t[sum-num] += cnt;
}
m = t;
}
return m[S];
}
};