注:
题目:
给你一个整数数组 nums 和一个整数 target 。
向数组中的每个整数前添加 ‘+’ 或 ‘-’ ,然后串联起所有整数,可以构造一个 表达式 :
例如,nums = [2, 1] ,可以在 2 之前添加 ‘+’ ,在 1 之前添加 ‘-’ ,然后串联起来得到表达式 “+2-1” 。
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。
示例 1:
输入:nums = [1,1,1,1,1], target = 3
输出:5
解释:一共有 5 种方法让最终目标和为 3 。
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3
示例 2:
输入:nums = [1], target = 1
输出:1
提示:
1 <= nums.length <= 20
0 <= nums[i] <= 1000
0 <= sum(nums[i]) <= 1000
-1000 <= target <= 1000
题解:
思路
假设加法的总和为x,那么减法对应的总和就是sum - x。
所以我们要求的是 x - (sum - x) = target
x = (target + sum) / 2
此时问题就转化为,装满容量为x背包,有几种方法。
动态规划过程如下:
确定dp数组以及下标的含义
定义二维数组 dp,其中dp[i][j] 表示在数组nums[0]到nums[i]中选取元素,使得这些元素之和等于j的方案数。
假设数组 nums 的长度为 n,则最终答案为 dp[n-1][bagsize]。
确定递推公式
如果 j<num,则不能选 num,此时有 dp[i][j]=dp[i−1][j];
如果 j≥num,则如果不选 }num,方案数是dp[i−1][j],如果选 num,方案数是 dp[i−1][j−num],此时有dp[i][j]=dp[i−1][j]+dp[i−1][j−num]。
dp数组如何初始化
当没有任何元素可以选取时,元素和只能是 0,对应的方案数是 1,因此动态规划的边界条件是:
dp[0][0]=1
除此之外,当nums[0]==背包容量j时,可以选择nums[0]以满足背包容量的要求,即dp[0][j]=1
确定遍历顺序
先遍历物品,再遍历背包容量
复杂度分析
时间复杂度O(n * m),n为正数个数,m为背包容量
空间复杂度:O(n*m)
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum=0;
for(int i:nums){
sum+=i;
}
if(sum+target<0||((sum+target)%2==1)){
return 0;
}
int bagsize=(sum+target)/2;
//dp[i][j]在数组nums[0]-nums[i]中选取元素,使得这些元素之和等于j的方案数
vector<vector<int>> dp(nums.size(),vector<int>(bagsize+1,0));
for(int j=0;j<=bagsize;j++){//初始化
if(j==0){
dp[0][j]=1;
}
if(nums[0]==j){
dp[0][j]++;
}
}
for(int i=1;i<nums.size();i++){
for(int j=0;j<=bagsize;j++){
if(nums[i]>j){
dp[i][j]=dp[i-1][j];
}
else{
dp[i][j]=dp[i-1][j]+dp[i-1][j-nums[i]];
}
}
}
return dp[nums.size()-1][bagsize];
}
};
优化空间复杂度至O(m):
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum=0;
for(int i:nums){
sum+=i;
}
if(sum+target<0||((sum+target)%2==1)){
return 0;
}
int bagsize=(sum+target)/2;
//dp[i][j]在数组nums[0]-nums[i]中选取元素,使得这些元素之和等于j的方案数
vector<int> dp(bagsize+1,0);
for(int j=0;j<=bagsize;j++){
if(j==0){
dp[0]=1;
}
if(nums[0]==j){
dp[j]++;
}
}
for(int i=1;i<nums.size();i++){
for(int j=bagsize;j>=nums[i];j--){
if(nums[i]>j){
dp[j]=dp[j];
}
else{
dp[j]=dp[j]+dp[j-nums[i]];
}
}
}
return dp[bagsize];
}
};