题目:
给你一个整数数组 nums 和一个整数 target 。
向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :
例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。
示例:
解法:
这次和之前遇到的背包问题不一样了,之前都是求容量为 j 的背包,最多能装多少。
本题则是装满有几种方法。其实这就是一个组合问题了。
(1)确定dp数组以及下标的含义
dp[j] 表示:填满 j(包括j)这么大容积的包,有dp[j]种方法。
(2)确定递推公式:dp[j] += dp[j - nums[i]]
示例1中,j=4,target=3,nums总和为背包容量=5,那么背包容量=(abs(target)+nums)/2
当背包里已经有一个1(nums[i]) 的话,有 dp[3]种方法 凑成 容量为4的背包。
当背包里已经有一个2(nums[i]) 的话,有 dp[2]种方法 凑成 容量为4的背包。
当背包里已经有一个3(nums[i]) 的话,有 dp[1]种方法 凑成 容量为4的背包。
当背包里已经有一个4(nums[i]) 的话,有 dp[0]种方法 凑成 容量为4的背包。
(3)dp数组如何初始化
如果数组为[0] ,target = 0,那么 bagweight = (target + sum) / 2 = 0。 dp[0]也应该是1, 也就是说给数组里的元素 0 前面无论放加法还是减法,都是 1 种方法。
(4)确定遍历顺序
对于01背包问题一维dp的遍历,nums放在外循环,target在内循环,且内循环倒序。
(5)举例推导dp数组
输入:nums: [1, 1, 1, 1, 1], target: 3
bagweight = (target + sum) / 2 = (3 + 5) / 2 = 4
当背包里已经有一个1(nums[i]) 的话,有 dp[3]种方法 凑成 容量为4的背包。
当背包里已经有一个2(nums[i]) 的话,有 dp[2]种方法 凑成 容量为4的背包。
当背包里已经有一个3(nums[i]) 的话,有 dp[1]种方法 凑成 容量为4的背包。
当背包里已经有一个4(nums[i]) 的话,有 dp[0]种方法 凑成 容量为4的背包。
也就是,当背包里有一个nums[i]时,有dp[j-nums[i]]种方法成 容量为j的背包。
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target)
{
int sum=accumulate(nums.begin(),nums.end(),0);
if((sum+abs(target))%2==1) return 0;
if(abs(target)>sum) return 0;
int bagweight = (sum+abs(target))/2;//背包容量
vector<int> dp(bagweight+1,0);//dp[j]:容量为j的背包能由几种方法凑成
dp[0]=1;
for(int i=0;i<nums.size();i++)
{
for(int j=bagweight;j>=nums[i];j--)
{
dp[j] += dp[j - nums[i]];
}
}
return dp[bagweight];
}
};