LeetCode第213题:打家劫舍Ⅱ

题干

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

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

示例 1:

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

思路:动态规划

这道题的基本大意就是将nums设置环形,那我们就需要考虑第一个元素与最后一个元素,因为它们两者不能连续。

因此我们需要分两种情况,就是有第一个元素与没有第一个元素的情况。我们可以将这两种情况拆解成两个基础打家劫舍问题。保证首位不重合。这就需要我们留意dp数组的起始值了。

代码实现:

执行用时:96 ms, 在所有 JavaScript 提交中击败了21.01%的用户

内存消耗:40.6 MB, 在所有 JavaScript 提交中击败了5.02%的用户

var rob = function (nums) {
    /* 
    将打家劫舍第一个版本拆解成了两个不同的结构
     */
    if (nums.length == 1) {
        return nums[0]
    }
  	//分两种情况,就是使前后元素不相遇的情况,注意参数值
    let oneVersion = doRob(nums, 0, nums.length - 1)
    let twoVersion = doRob(nums, 1, nums.length)
    return oneVersion > twoVersion ? oneVersion : twoVersion
};
/* 
这里的操作与打家劫舍相同,只是初始值不同
 */
function doRob(nums, begin, end) {
    let dp = [];
    dp[0] = nums[begin]
    dp[1] = nums[begin + 1]>nums[begin]?nums[begin+1]:nums[begin]
  	//拆解后dp数组只有两个元素的情况
    if (end - begin == 2) {
        return dp[0] > dp[1] ? dp[0] : dp[1]
    }
  	//我这里循环dp数组给其加元素,所以长度就是end-begin,你也可以遍历nums数组,就是需要注意我们的dp数组应该与nums数组的长度一致。
    for (let i =2; i < end-begin; i++) {
        dp[i] = Math.max(nums[i+begin] + dp[i - 2], dp[i - 1])
    }
  //最后返回dp数组的最后一位
    return dp[end-begin - 1]
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享