1 描述
在上次打劫完一条街道之后,窃贼又发现了一个新的可以打劫的地方,但这次所有的房子围成了一个圈,这就意味着第一间房子和最后一间房子是挨着的。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,该系统会自动报警。
给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,在不触动报警装置的情况下, 你最多可以得到多少钱 。
这题是House Robber的扩展,只不过是由直线变成了圈
2 样例
2.1 样例1
输入: nums = [3,6,4]
输出: 6
2.2 样例2
输入: nums = [2,3,2,3]
输出: 6
3 题解
3.1 解题思路和方法
解决这种问题的思路是首先要破圈,将圈破坏掉这样就成了打劫房子的题型了;
由于房子0和房子n - 1 是相临的,那我们可以分别假设不偷房子0和房子n - 1时可以偷的最大金币数;这样就形成了两个直线型的问题。
3.2 算法实现
- calc()函数用来统计当前的序列能打劫的最大金币数
- houseRobber2()函数中的两次for循环主要是要为了去处理不偷房子0和不偷房子n - 1的这两种情况,最后再统计两种情况能打劫的最大金币数。
public class Solution {
public int calc(int[] a) {
int n = a.length;
if (n == 0) {
return 0;
}
if (n == 1) {
return a[0];
}
int old = 0;
int now = a[0];
for (int i = 2; i <= n; i++) {
int tmp = Math.max(now, old + a[i - 1]);
old = now;
now = tmp;
}
return now;
}
/**
* @param nums: An array of non-negative integers.
* @return: The maximum amount of money you can rob tonight
*/
public int houseRobber2(int[] nums) {
// write your code here
int n = nums.length;
if (n == 0) {
return 0;
}
if (n == 1) {
return nums[0];
}
int[] a = new int[n - 1];
/* 不偷房子n - 1 的处理 */
for (int i = 0; i < n - 1; i++) {
a[i] = nums[i];
}
int res = calc(a);
/* 不偷房子0的处理 */
for (int i = 0; i < n - 1; i++) {
a[i] = nums[i + 1];
}
res = Math.max(res, calc(a));
return res;
}
}