持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 17 天,点击查看活动详情
题目链接
题目描述
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
测试用例
用例1:
输入: nums = [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
限制
1 <= nums.length <= 1000 <= 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();
}
};