Note: This is an extension of House Robber.
After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This time, all houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in the previous street.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.
题目分析:与前一题相比只是变成了环,基础做法:dp[0/1][i][0/1]表示第一间不偷/偷的情况下第i间不偷/偷的最大值,最后有四种结果,但第一间和最后一间都偷的属于不合法情况
public class Solution {
public int rob(int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
}
if (n == 1) {
return nums[0];
}
int[][][] dp = new int[2][n + 1][2];
dp[1][0][1] = nums[0];
for (int i = 1; i < n; i ++) {
dp[1][i][0] = Math.max(dp[1][i - 1][0], dp[1][i - 1][1]);
dp[0][i][0] = Math.max(dp[0][i - 1][0], dp[0][i - 1][1]);
dp[1][i][1] = dp[1][i - 1][0] + nums[i];
dp[0][i][1] = dp[0][i - 1][0] + nums[i];
}
return Math.max(dp[0][n - 1][1], Math.max(dp[0][n - 1][0], dp[1][n - 1][0]));
}
}
同样可以优化空间为O(1)
public class Solution {
public int rob(int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
}
if (n == 1) {
return nums[0];
}
int yesFirPre1 = nums[0], yesFirPre0 = 0;
int noFirPre1 = 0, noFirPre0 = 0;
int yesFirCur1 = 0, yesFirCur0 = 0;
int noFirCur1 = 0, noFirCur0 = 0;
for (int i = 1; i < n; i ++) {
yesFirCur0 = Math.max(yesFirPre0, yesFirPre1);
noFirCur0 = Math.max(noFirPre0, noFirPre1);
yesFirCur1 = yesFirPre0 + nums[i];
noFirCur1 = noFirPre0 + nums[i];
yesFirPre0 = yesFirCur0;
yesFirPre1 = yesFirCur1;
noFirPre0 = noFirCur0;
noFirPre1 = noFirCur1;
}
return Math.max(noFirPre0, Math.max(noFirPre1, yesFirPre0));
}
}
这题也可以这样想,头和尾不能同时偷,那么问题可以转换为两个直线上的子问题0~n-1和1~n,然后用前一题的方式求解
public class Solution {
public int rob(int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
} else if (n == 1) {
return nums[0];
}
return Math.max(robLine(nums, 1, n), robLine(nums, 0, n - 1));
}
public int robLine(int[] nums, int l, int r) {
int pre1 = nums[l], pre0 = 0, cur1 = 0, cur0 = 0;
for (int i = l + 1; i < r; i ++) {
cur0 = Math.max(pre1, pre0);
cur1 = pre0 + nums[i];
pre1 = cur1;
pre0 = cur0;
}
return Math.max(pre0, pre1);
}
}