要求:非负数组,给元素加负号求和等于target的种数
思路:回溯是O(2^n)太慢了,和等于target可以考虑01背包。添加负号元素之和pn(这里是正的),则正号和为sum-pn,则sum-pn-pn=target,pn=(sum-target)/2,即求能不能使和为pn的01背包问题,每个数只能用一次,dp[i][j]表示i个数构成和为j的次数,递推时要相加
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int n=nums.size();
int sum=0;
for(int i=0;i<n;++i)
sum+=nums[i];
if((sum-target&1)||sum-target<0)return 0;
int pn=(sum-target)/2;
int dp[n+1][pn+1];
for(int j=0;j<=pn;++j)
dp[0][j]=0;
dp[0][0]=1;
for(int i=1;i<=n;++i){
for(int j=0;j<=pn;++j){
if(j>=nums[i-1])
dp[i][j]=dp[i-1][j-nums[i-1]]+dp[i-1][j];
else dp[i][j]=dp[i-1][j];
}
}
return dp[n][pn];
}
};
优化空间
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int n=nums.size();
int sum=0;
for(int i=0;i<n;++i)
sum+=nums[i];
if((sum-target&1)||sum-target<0)return 0;
int pn=(sum-target)/2;
int dp[pn+1];
for(int j=0;j<=pn;++j)
dp[j]=0;
dp[0]=1;
for(int i=1;i<=n;++i){
for(int j=pn;j>=0;--j){
if(j>=nums[i-1])
dp[j]=dp[j-nums[i-1]]+dp[j];
}
}
return dp[pn];
}
};
再加个简单回溯时间很慢
class Solution {
public:
int dfs(vector<int>& nums, int& target,int sum,int index){
if(sum==target&&index==nums.size())return 1;
if(index>=nums.size())return 0;
return dfs(nums,target,nums[index]+sum,index+1)+dfs(nums,target,-nums[index]+sum,index+1);
}
int findTargetSumWays(vector<int>& nums, int target) {
return dfs(nums,target,0,0);
}
};