一起刷LeetCode——目标和(背包问题)

272 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情

目标和

给你一个整数数组 nums 和一个整数 target 。向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

分析

  • 给定一个数组和一个target,数组中的数可以取正值或者负值,给出运算结果等于target的方法数。把target设置为包的容量,把数组比作物品,数字取正值或者负值比作物品的价值,每个数字只能使用一次,就很像01背包问题,但是与01背包问题不同的是需要把所有的物品都装到背包里,正好达到背包的容量。背包问题使用dp来解决,因此确定一下dp状态的定义和状态转移

  • 状态定义: dp(i,sum)表示遍历到数组的第i个位置时,使得当前的和为sum的方法数

  • 状态转移:

    • 当取正值时,dp(i+1,sum) = dp(i,sum+nums[i])
    • 当取负值时,dp(i+1, sum) = dp(i,sum-nums[i])
  • 答案就是dp(nums.length-1,target),当和为target并且遍历完数组后得到的方法数

  • 优化:记忆化动态规划,把之前算过的子问题存住,可以有效提升算法效率,一般记忆化的数据都会存在Map中,由于我们的dp状态定义,可以把key设置为状态中的两个参数

代码

var findTargetSumWays = function(nums, target) {
    const map = new Map()
    function dp(idx, sum) {
        if(idx === nums.length) return sum === target ? 1 : 0
        if(map.has(`${idx}-${sum}`)) return map.get(`${idx}-${sum}`)
        const res = dp(idx+1, sum+nums[idx]) + dp(idx+1, sum-nums[idx])
        map.set(`${idx}-${sum}`, res)
        return res
    }
    return run(0, 0)
};

总结

  • 今天依旧是01背包问题的变体,能通过题目描述分析到是背包问题可能还是有些难度,在确定了背包问题后,因为01背包问题是一类典型的dp问题,所以题解很快就能写出来,应该更多的时间放在审题上
  • 今天也是有收获的一天