动态规划:打家劫舍 ⛄

162 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

打家劫舍

题目地址: leetcode-cn.com/problems/ho…

题目描述:

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4
输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12

题目分析

本题是一道非常经典的动态规划算法题目,在本题当中,可能一开始会先想到使用贪心算法进行局部最优解进行偷窃,但是最后一步一步取最优对本题是会走进死胡同的。

本题应该像之前做前缀和类似,定义一个sum数组,这是用来记录从第一家开始到最后一家,到达每一家时能获取到的最大金额。

首先第一家金额肯定是nums[0],而到第二家最大金额是Math.max(nums[0], nums[1]),第一家与第二家做对比,取金额更大的一家。

第三家的金额则是Math.max(nums[1], nums[0]+nums[2]),因为打家劫舍不能够相邻,所以第三家可以累积的最大金额是第二家金额与(第一家 + 第三家)金额做对比。

同理,后面的每一家金额也是类似于第三家的累积金额获取方式

[1,2,3,1]为例,得到的sum数组为[1,2,4,4]

image.png

最终返回结果是sum[sum.length - 1]


代码

var rob = function(nums) {
    var len = nums.length;
    if (len == 0) return 0;
    if (len == 1) return nums[0];

    // 定义一个数组,存放从第一家开始每一家能积攒下来的金额
    var sum = [];
    sum[0] = nums[0];
    sum[1] = Math.max(nums[1], nums[0]);
    for(let i = 2; i < len; i++) {
        sum[i] = Math.max(sum[i - 1], sum[i - 2] + nums[i]);
    }
    return sum[len - 1]
};