494. 目标和
给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。
返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
示例 1:
输入: nums: [1, 1, 1, 1, 1], S: 3
输出: 5
解释:
-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
一共有5种方法让最终目标和为3。
递归
直接递归思路简单,深度优先搜索,但会重复计算,导致效率降低
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
int res = 0;
dfs(nums,S,0,res);
return res;
}
void dfs(vector<int>& nums,int S,int start,int& res)
{
if(start >= nums.size())
{
if(S == 0)
{
res++;
}
return;
}
dfs(nums,S-nums[start],start+1,res);
dfs(nums,S+nums[start],start+1,res);
}
};
记忆化递归
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
vector<unordered_map<int,int> > dp(nums.size()); //标记计算过的点
return dfs(nums,S,0,dp);
}
int dfs(vector<int>& nums,int sums,int n,vector<unordered_map<int,int>>& dp)
{
if(n == nums.size()) return sums == 0; //等于0,返回1;不等0,返回0
if(dp[n].count(sums)) return dp[n][sums]; //计算过的点,直接返回,避免重复计算
int cnt1 = dfs(nums,sums-nums[n],n+1,dp); //为‘-’的情况
int cnt2 = dfs(nums,sums+nums[n],n+1,dp); //为‘+’的情况
return dp[n][sums] = cnt1+cnt2; //两种情况相加,并用数组记录
}
};