LeetCode - 213. 打家劫舍 II

171 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。


原题:213. 打家劫舍 II
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。

解题思路:

这道题与 198. 打家劫舍 相似,它解题思路在这里。本题的解题思路介绍也会从这道题的解题思路向下扩展。

本题与之前的题不同的是,房屋是一个环状的结构,也就是第一个房屋和最后一个房屋是相连的,根据规则,两个相邻的房屋不能都进行偷窃,因此,第一个房屋和最后一个房屋只能偷一个。

在上一道题中,使用了动态规划的方法,这道题依然可以使用这种方法。使用与上一题类似的动态规划方法的前提,是需要有一个初始状态,因此这道题解题的时候,我们还是可以暂时把它看成一个有头有尾的房屋数组,而不是一个环状,只不过要分成两种情况来考虑:

  1. 偷第一个房屋,不偷最后一个房屋。
  2. 偷最后一个房屋,不偷第一个房屋。

假设一共有 n 个房屋,房屋中包含的先进保存在数组 nums[n] 中,那么这两种情况对应的数组区间分别是:

  1. 下标从 0n - 2 的子数组。
  2. 下标从 1n - 1 的子数组。

然后,对以上两个字数组分别进行上一题中用到的方法求出结果,再取两个结果中较大的一个,既是本题的最后结果。

最终代码:

class Solution {
    public int rob(int[] nums) {
        int length = nums.length;
        if (length == 1) {
            return nums[0];
        }
        return Math.max(robRange(nums, 0, length - 2), robRange(nums, 1, length - 1));
    }
    public int robRange(int[] nums, int start, int end) {
        int y = 0, n = 0;
        for (int i = start; i <= end; i++) {
            int num = nums[i];
            int temp = n + num;
            n = Math.max(y, n);
            y = temp;
        }
        return Math.max(y, n);
    }
}