通过问题分析可知,对于这个target应该是由nums两个子集和的差值求出
即sum_n - sum_m = target
,则sum + sum_n - sum_m = sum + target
,由于sum - sum_m = sum_n
,得出2 * sum_n = sum + target
,化简得sum_n = (sum + target) / 2
且如果存在可以相减得出target
的话sum + target
一定是偶数(sum + target = 2 * sum_n
)
这个题就可以转化成为求sum数组中一个和为sum_n的子串个数(这里一定是和为sum_n, 因为当target为正数的时候sum_n > sum_m
,sum_m很可能是一个负数),转换成一个可以组成目标value解的个数的背包问题
这个题一维DP比二维DP好想
一维DP
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for(int i = 0; i < nums.size(); i++)
sum += nums[i];
if((target + sum) % 2 || target + sum < 0)
return 0;
int n = (target + sum) / 2;
vector<int> dp(n + 1, 0);
dp[0] = 1;
for(int i = 0; i < nums.size(); i++)
{
//一维DP,从后往前,防止一个nums[i]多次计入
for(int j = n; j >= nums[i]; j--)
dp[j] += dp[j - nums[i]];
}
return dp[n];
}
};
二维DP
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for(int i = 0; i < nums.size(); i++)
sum += nums[i];
if((target + sum) % 2 || target + sum < 0)
return 0;
int n = (target + sum) / 2;
vector<vector<int>> dp(nums.size() + 1, vector<int>(n + 1, 0));
dp[0][0] = 1;
for(int i = 1; i <= nums.size(); i++)
{
for(int j = 0; j < n + 1; j++)
{
dp[i][j] = dp[i - 1][j];
if(j >= nums[i - 1])
dp[i][j] += dp[i - 1][j - nums[i - 1]];
}
}
return dp[nums.size()][n];
}
};