动态规划打家劫舍问题02:打家劫舍Ⅱ

71 阅读1分钟

打家劫舍Ⅱ

力扣213. 打家劫舍 II - 力扣(LeetCode)
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
示例 1:
输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2:
输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。 示例 3: 输入: nums = [1,2,3]
输出: 3
提示:

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

这道题⽬和动态规划打家劫舍问题01:打家劫舍 - 掘金 (juejin.cn)是差不多的,唯⼀区别就是成环了。对于⼀个数组,成环的话主要有如下三种情况:

  • 情况⼀:考虑不包含⾸尾元素:

image.png

  • 情况⼆:考虑包含⾸元素,不包含尾元素:

image.png

  • 情况三:考虑包含尾元素,不包含⾸元素

image.png
注意我这⾥⽤的是"考虑",例如情况三,虽然是考虑包含尾元素,但不⼀定要选尾部元素! 对于情况三,取nums[1] 和 nums[3]就是最⼤的。⽽情况⼆ 和 情况三 都包含了情况⼀了,所以只考虑情况⼆和情况三就可以了。
分析到这⾥,本题其实⽐较简单了。 剩下的和198.打家劫舍就是⼀样的了。
java代码如下:

class Solution {
    public int rob(int[] nums) {
        int l = nums.length;
        if(l == 1)
            return nums[0];
        int max1 = get(nums, l, 0, l - 2);
        int max2 = get(nums, l, 1, l - 1);
        return max1 >= max2 ? max1 : max2;
    }
    public static int get(int[] nums, int l, int left, int rigth){
        if(left == rigth)
            return nums[left];
    int[] dp = new int[l];
    dp[left] = nums[left];
    dp[left + 1] = Math.max(nums[left], nums[left + 1]);
    for(int i = left + 2; i <= rigth; i++)
        dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
    return dp[rigth];
    }
}