494. Target Sum
问题描述:
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.
解题思路:
这道题首先想到了dfs,对每一位数字的每一种可能行进行枚举,并统计数字。
我的dfs运行时间为424ms
但是依旧有10+ms的解法,那就是DP!
看了一下Grandyang的总结,这里其实使用dp来存储已经访问过的情况从而避免多次访问。
dp[start][sum]为在该起点(start)下可以获得的组合个数。
代码:
DFS:
class Solution { public: int findTargetSumWays(vector<int>& nums, int S) { int ret = 0; dfs(nums, 1, 0, S, ret); dfs(nums, -1, 0, S, ret); return ret; } private: void dfs(vector<int>& nums, int sign, int idx, int curVal, int &ret){ curVal -= nums[idx] * sign; if(idx == nums.size()-1){ if(curVal == 0) ret++; return; } idx++; dfs(nums, 1, idx, curVal, ret); dfs(nums, -1, idx, curVal, ret); } };
DP:
class Solution { public: int findTargetSumWays(vector<int>& nums, int S) { vector<unordered_map<int, int>> dp(nums.size()); return helper(nums, S, 0, dp); } int helper(vector<int>& nums, int sum, int start, vector<unordered_map<int, int>>& dp) { if (start == nums.size()) return sum == 0; if (dp[start].count(sum)) return dp[start][sum]; int cnt1 = helper(nums, sum - nums[start], start + 1, dp); int cnt2 = helper(nums, sum + nums[start], start + 1, dp); return dp[start][sum] = cnt1 + cnt2; } };