。。最近背包问题做得好崩溃
这题的解法和 分割子集、石头 差不多
分成两个集合 (注意这里计算的时候是不带上符号的,只是单纯的数字
a. 正号 的数字集合 P
b. 负号 的数字集合 N
所以就有以下公式
sum(P) + sum(N) = sum(nums)
sum(P) - sum(N) = target
所以
sum(P) = (target + sum(nums)) / 2
所以
需要求出和为 (target + sum(nums)) / 2 的方案有多少个
1.dp 数组的含义
dp [ j ]
下标:和为 j
值: 和为 j 的方案有多少个
2.递推公式
dp [ j ] = dp [ j ] + dp [ j - nums[ i ] ]
不选i : dp [ j ]
选i :dp [ j - nums[ i ] ]
意思是,如果选择了 i , 则 剩下要组成和为j - nums [ i ] 的方案数就等于dp[ j - nums [ i ] ]
3.初始化
dp [ 0 ] = 1
这有点绕。。就当作是 和 为0 的方式 只有一种。
例如:集合 [ 0 ] target = 0 , 此时就只有一种方法
4. 遍历顺序
和之前一样,物品正序,背包倒叙
注意:
有两个判断
如果不能整除 2 , 就说明没有找到 pos,因为是元素都是整数!
如果target 的绝对值大于 sum,说明不可能找到方案
图源力扣官方题解
if((sum + target) % 2 == 1) return 0;
if(abs(target) > sum) return 0;
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for(int a : nums)
{
sum += a;
}
int pos = (target + sum) / 2;
if((sum + target) % 2 == 1) return 0;
// 要加绝对值
if(abs(target) > sum) return 0;
vector<int> dp(pos + 1, 0);
dp[0] = 1;
for(int i = 0; i < nums.size(); i++)
{
for(int j = pos; j >= nums[i]; j--)
dp[j] = dp[j] + dp[j - nums[i]];
}
return dp[pos];
}
};