题目描述:
给你一个整数数组 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
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/ta… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
01背包🎒问题转换:
本题的难点是01背包问题的转换:
01背包问题是选或者不选,在本题中时nums数组元素必选,而选或者不选的是+或者-号;
- 先将本题转换为01背包问题;
- 假设满足要求的表达式中:所有符号为+的元素之和为x;所有符号为-的元素之和的绝对值为y;
- 则我们想要的结果target=x-y;
- 而已知x和y之和即为数组之和sum=x+y;
- 由以上两个公式求得x=(target+sum)/2
- 将问题转换为nums中挑选出几个数其和为x;
- 转化为01背包🎒装满问题:容量为x的,物品为nums数组的01背包🎒问题; 动态规划四部曲:
- 确定dp含义
- dp数组定义:dp[j]代表填满容量为j的背包🎒总共有dp[j]种方法;
- 确定dp公式:dp[j] = dp[j] + dp[j - num],
- dp数组初始化:
- 初始化容量为x的dp数组为0;
- 且dp[0]=1;实际含义:填满容量为0的背包只有1中方法;
- 遍历顺序:
- 01背包一定是外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!
时空复杂度
- 时间复杂度:O(n * x) 两层for循环;n为nums.length;
- 空间复杂度:O(x))
代码
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var findTargetSumWays = function(nums, target) {
let sum=0;
for(let num of nums){
sum+=num
}
// 当目标值大于数组元素的最大值,即所有元素选择+的情况;
if(target>sum){
return 0;
}
// 如果x不是整数,即(target+sum)不是偶数,则不可能实现;
if((target+sum)%2==1){
return 0;
}
//dp数组定义:dp[j]代表填满容量为j的背包🎒总共有dp[j]种方法;
// 最大容量x
let x=Math.floor((target+sum)/2);
// dp初始化;dp[0]=1,实际含义:填满容量为0的背包只有1中方法;
let dp=new Array(x+1).fill(0);
dp[0]=1;
// 递推公式dp[j]=dp[j]+dp[j-nums[i]]
for(let num of nums){
for(let j=x;j>=num;j--){
dp[j]=dp[j]+dp[j-num]
}
}// end of for
return dp[x]
};