题干:给你一个整数数组 nums
和一个整数 target
。
向数组中的每个整数前添加 '+'
或 '-'
,然后串联起所有整数,可以构造一个 表达式 :
例如,nums = [2, 1]
,可以在 2
之前添加 '+'
,在 1
之前添加 '-'
,然后串联起来得到表达式 "+2-1"
。返回可以通过上述方法构造的、运算结果等于 target
的不同 表达式 的数目。
示例:
输入: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
解题思路:动态规划之01背包
该题主要的切入点就是要将整个表达式拆解成若干正数与若干负数相加。
假设为正数的数字和为:plus ,为负数的数字和则为: nums 之和 - plus
而 plus - ( nums 之和 - plus ) = target
解方程可得 plus = ( nums 之和 + target ) / 2
令背包的容积为 plus ,物品为nums[i] 来求解能使题目构成01背包问题。
下面就是动态规划的常规五步:
-
确定dp数组(dp table)以及下标的含义
dp[j] 表示填满 j(包括 j)容积(正数和),有 dp[j] 种方法
-
确定递推公式
背包解决求方法数问题 ⇒ 累加法
由dp数组的含义可得,dp[ j - nums[i] ] 表示不考虑 nums[i] 的方法数,dp[j] 应等于考虑每个nums[i] 的方法数的和,而每个nums[i] 的方法数其实就等于不考虑 nums[i] 的方法数。
dp[j] += dp[j - nums[i]]
-
dp数组如何初始化
dp[0] = 1,意思是装满容量为0的背包,有1种方法,就是装0件物品。
-
确定遍历顺序
for(let i=0; i<nums.length; i++){ for(let j=bagWeight; j>=nums[i]; j--){ dp[j]+=dp[j-nums[i]] } }
-
举例推导dp数组
大家可以用示例题自己推导看看dp[j] 的值是否如上文分析的一致。
JavaScript 代码如下:
var findTargetSumWays = function(nums, target) {
let sum = nums.reduce((a,b)=>a+b)
if((sum+target) % 2 == 1) return 0;
let bagWeight = (sum+target)/2;
let dp = new Array(bagWeight+1).fill(0);
dp[0] = 1;
for(let i=0; i<nums.length; i++){
for(let j=bagWeight; j>=nums[i]; j--){
dp[j]+=dp[j-nums[i]]
}
}
return dp[bagWeight]
};
注:代码中 Array.reduce() 这个遍历函数用于求和非常有帮助,大家可以去搜搜它的具体用法,这样就不用每次用 for 循环写大段代码啦!