目标和-01背包

33 阅读1分钟

494. 目标和

给你一个非负整数数组 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. 首先这个题目要学会怎么通过数学转换 01背包
  2. 这个题目的初始化,要通过手写dp才能更加的清楚
  3. 要明确一点,当当前的容量为1的时候,你其实这个时候也要去考虑,因为不放也是一种解
  4. 其次对于math库的常见方法要熟悉,比如求指数运算
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var findTargetSumWays = function (nums, target) {
    let sum = nums.reduce((a, b) => a + b);
    if ((sum + target) % 2 !== 0) {
        return 0
    }
    // 边界条件
    if (Math.abs(target) > sum) return 0; // 此时没有方案 
    let res = (target + sum) / 2


    let dp = new Array(nums.length + 1).fill(0).map(() => new Array(res + 1).fill(0))
    dp[0][0] = 1;
    for (let i = 0; i <= res; i++) {
        dp[0][nums[0]] = 1
    }
    let count = 0
    for (let j = 0; j < nums.length; j++) {
        if (nums[j] === 0) {
            count++
            dp[j][0] = Math.pow(2, count)
        } else {
            dp[j][0] = 1
        }

    }


    for (let i = 1; i < nums.length; i++) {
        for (j = 0; j <= res; j++) {

            if (j >= nums[i]) {
                dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i]]
            } else {
                dp[i][j] = dp[i - 1][j]
            }

        }
    }
    return dp[nums.length - 1][res]

};