1.题目描述:
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,今晚能够偷窃到的最高金额。
2.动态规划:
与leetcode198. 打家劫舍思路几乎一致,但是数组的头尾也不能相连,做法其实就是分别把首尾元素排除掉(选择时也只是考虑上首尾元素,不一定真正选,是否选择在动态规划代码中得出),计算两次198的打家劫舍即可。
class Solution {
public int rob(int[] nums) {
if (nums.length == 1) return nums[0];
if (nums.length == 2) return Math.max(nums[0], nums[1]);
int maxLeft = helper(nums, 0, nums.length - 2);
int maxRight = helper(nums, 1, nums.length - 1);
return Math.max(maxLeft, maxRight);
}
public int helper(int[] nums, int left, int right) {
int[] dp = new int[right - left + 1];
dp[0] = nums[left];
dp[1] = Math.max(nums[left], nums[left + 1]);
for (int i = 2; i < dp.length; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i + left]);
}
return dp[dp.length - 1];
}
}
状态压缩:
class Solution {
public int rob(int[] nums) {
if (nums.length == 1) return nums[0];
if (nums.length == 2) return Math.max(nums[0], nums[1]);
int maxLeft = helper(nums, 0, nums.length - 2);
int maxRight = helper(nums, 1, nums.length - 1);
return Math.max(maxLeft, maxRight);
}
public int helper(int[] nums, int left, int right) {
int[] dp = new int[2];
dp[0] = nums[left];
dp[1] = Math.max(nums[left], nums[left + 1]);
for (int i = left + 2; i <= right; i++) {
int temp = dp[1];
dp[1] = Math.max(dp[1], dp[0] + nums[i]);
dp[0] = temp;
}
return dp[1];
}
}