力扣【动态规划专题】213. 打家劫舍 II

189 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 17 天,点击查看活动详情

题目链接

213. 打家劫舍 II - 力扣(LeetCode)

题目描述

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

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

测试用例

用例1:

输入: nums = [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

限制

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 1000

题目分析

题目需要我们从给定的数组中,提取若干个互不相邻的元素,求其最大值

不相邻即意味着,符合要求的数,在数组中,起码会间隔1个元素,因此,我们可以推导出一个状态转移的公式:f(n) = Math.max(f(n-1), f(n-2) + f(n))

arr 长度为 1 时,最大值就是 arr[0];当 arr 长度为 2 时,最大值就是 arr[0], arr[1] 中的某一个

此外,题目还要求,数组的第一项、和最后一项,不能同时选中。 用下标来描述,即有 0 就无 n,有 n 就无 0。换个思路,将他拆分为 2 个数组,长度分别为 [0, n-1], [1, n],用动态规划分别求他们各自的最大值,最后再取其中一个即可

代码实现

完整的代码实现如下

var rob = function (nums) {
    if (nums.length == 1) return nums[0];
    if (nums.length == 2) return Math.max(nums[0], nums[1]);
    return Math.max(max(nums.slice(0, nums.length - 1)), max(nums.slice(1, nums.length)))
    function max(arr) {
        arr[1] = Math.max(arr[0], arr[1]);
        for (let i = 2; i < arr.length; i++) {
            arr[i] = Math.max(arr[i - 1], arr[i - 2] + arr[i]);
        }
        return arr.pop();
    }
};

image.png