小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
原题:213. 打家劫舍 II
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
解题思路:
这道题与 198. 打家劫舍 相似,它解题思路在这里。本题的解题思路介绍也会从这道题的解题思路向下扩展。
本题与之前的题不同的是,房屋是一个环状的结构,也就是第一个房屋和最后一个房屋是相连的,根据规则,两个相邻的房屋不能都进行偷窃,因此,第一个房屋和最后一个房屋只能偷一个。
在上一道题中,使用了动态规划的方法,这道题依然可以使用这种方法。使用与上一题类似的动态规划方法的前提,是需要有一个初始状态,因此这道题解题的时候,我们还是可以暂时把它看成一个有头有尾的房屋数组,而不是一个环状,只不过要分成两种情况来考虑:
- 偷第一个房屋,不偷最后一个房屋。
- 偷最后一个房屋,不偷第一个房屋。
假设一共有 n 个房屋,房屋中包含的先进保存在数组 nums[n] 中,那么这两种情况对应的数组区间分别是:
- 下标从
0到n - 2的子数组。 - 下标从
1到n - 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);
}
}