[路飞]_leetcode-494-目标和

684 阅读3分钟

「这是我参与2022首次更文挑战的第32天,活动详情查看:2022首次更文挑战

[题目地址] [B站地址]

给你一个整数数组 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

解题思路

这个问题乍一看可能感觉有些复杂,每1个数字都有正负2种可能,2个数字就是4种可能,3个数字就是8种可能,而本题又要求运算结果等于 target 的不同表达式数目,emmmm....
其实我们可以换个角度看这个问题,当只有一个数字的时候,我们很确定的可以得到两个表达式的结果,x 和 -x,然后,又因为下一个数字无非也就是两种可能,正或者负,所以我们一个一个数字的推导过去,就可以得到前面的数字组合的所有可能的结果,最后获取所有数字都使用可以获取结果值为 target 的表达式的数目即可。这明显是一个推导的问题,所以我们可以用动态规划来做。
状态定义:根据上述的分析结果可以知道,这里面有两个变量,使用数字的数量和可以求得的结果值,所以我们定义二维 dp dp[i][j] 表示前 i 个数字可以求得 j 的表达式的数目。
转移方程:因为每一个数字只有两种可能,为正或负,所以 dp[i][j] 可以由前 i-1 个数字组合 j-x 得到,也可以由前 i-1 个数字组合 j+x 得到,x 是第 i 个数字的值,所以得到 dp[i][j] = dp[i-1][j-x]+dp[i-1][j+x]
有了状态定义和转移方程,接下来就去实现代码吧!💪

代码实现

var findTargetSumWays = function (nums, target) {
  // 获取输入数组的长度
  const len = nums.length,
  // 初始化 dp 数组
    dp = Array(len + 1)
    // 获取输入数组所有整数的和值
  let total = 0
  for (let i = 0; i < len; i++) total += nums[i]
  // 因为数字下标没有负数,但是表达式的结果可能为负数,所以拿到和值,基于和值做一个结果的偏移
  for (let i = 0; i <= len; i++) dp[i] = Array(total * 2).fill(0)
  // 初始化 dp[0][0] = 1
  dp[0][total] = 1
  // 初始化前 i 个数字的和值
  let sum = 0
  // 遍历 i,求每一层 dp
  for (let i = 1; i <= len; i++) {
    // 获取当前数字的值
    const x = nums[i - 1]
    // 获取前 i 个数字的和值
    sum += x
    for (let j = -sum; j <= sum; j++) {
      // 求解范围内的每个 dp
      // 这里要注意j-x和j+x可能超出了我们数组的下标,所以运算的时候要 || 0
      dp[i][j + total] = (dp[i - 1][j - x + total] || 0) + (dp[i - 1][j + x + total] || 0)
    }
  }
  // 返回所有数字都使用,求得 target 的表达式的数目
  // 同理,因为 target+total可能超出dp数组的下标,要拿 0 兜底
  return dp[len][target + total] || 0
}

至此我们就完成了 leetcode-494-目标和

如有任何问题或建议,欢迎留言讨论!👏🏻👏🏻👏🏻