这道题是01背包问题的变体,我们稍微转换一下思路。
假设num[]数组中所有的要加上+变为正数的数字和我们用Sum(P1)表示,
num[]数组中所有要加上-变为负数的数字和我们用Sum(P2)表示,则题目要求我们:
Sum(P1)-Sum(P2)=target
稍微变形一下:
2Sum(P1)=target+Sum(P1)+Sum(P2)
Sum(P1)=(target+Sum)/2
那么我们就可以转换这个题目为背包问题:
给你一个数组num[],让你从中选择几个数组,使得他们的和为(target+Sum)/2。请问可选择的组合数最多有多少?
这样就好求多了
按照背包问题的思路求解:
状态:可选的数字,要求达成的值
定义dp数组:dp[i][j]表示在前i个数字中可以凑出的和为j的组合数量
选择:每次选择装入背包或者不装入背包,则对于第i个元素,**dp[i][j]应等于不选择nums[i-1]装入背包时候的组合数量加上选择将nums[i-1]装入背包的组合数量之和。**即 dp[i][j]=dp[i-1][j]+dp[i-1][j-nums[i-1]]
Base Case: dp[i][0]=1
Target: 求dp[n][(target+Sum)/2]
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((target+sum)%2!=0) return 0;//处理特殊情况
int m=(target+sum)/2;
if(m<0) return 0;//处理特殊情况
vector<vector<int>> dp(n+1,vector<int>(m+1,0));
for(int i=0;i<n;i++)
dp[i][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
if(j-nums[i-1]<0)//若j-nums[i-1]<0 则没有别的选择,只能选不装
dp[i][j]=dp[i-1][j];
else
dp[i][j]=dp[i-1][j]+dp[i-1][j-nums[i-1]];
}
}
return dp[n][m];
}