题目

the leetcode link

打家劫舍 II
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。

给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。

示例 1:
输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2:
输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 3:
输入:nums = [0]
输出:0

提示:
1 <= nums.length <= 100
0 <= nums[i] <= 1000

思路

环拆成两个队列,对每个队列动态规划求最优解(这里需掌握: 打家劫舍1),然后比较两者取最大值

Q:环为什么能当成两个队列?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
A: 不妨列举出所有可能出现的最优偷取情况来验证
偷: 1
不偷:0
有一队列:[x, x, x, x, x, x, x, x, x] n个元素
0 ~ n-1队列最优解所有可能情况
情况1: [1, 0, x, x, x, x, 0, 1] 0
情况2: [1, 0, x, x, x, x, 1, 0] 0
情况3: [0, 1, x, x, x, x, 0, 1] 0
情况4: [0, 1, x, x, x, x, 1, 0] 0
1 ~ n 队列最优解所有可能情况
情况1: 0 [1, 0, x, x, x, x, 0, 1]
情况2: 0 [1, 0, x, x, x, x, 1, 0]
情况3: 0 [0, 1, x, x, x, x, 0, 1]
情况4: 0 [0, 1, x, x, x, x, 1, 0]
对于 0~n 队列,自己的最优解可能情况与上述所有情况取差集,得到自己的剩下最优解可能情况
剩下情况: [1, 0, x, x, x, x, x, 0, 1]
假设是 0~n 环结构,会发现,只有“剩下情况”不成立,其他情况均成立。
也就是说:
0~n 环最优解所有可能情况 = (0 ~ n-1)队列最优解所有可能情况 + (1 ~ n) 队列最优解所有可能情况

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {

public int rob(int[] nums) {
int n = nums.length;
if(n==1) return nums[0];
if(n==2) return Math.max(nums[0],nums[1]);
return Math.max(rob(nums,0,n-1),rob(nums,1, n));
}

int rob(int[] nums, int start, int end){
//动态规划 dp空间优化为first,second
int first= nums[start];
int second = Math.max(first, nums[start+1]);
for(int i=start+2; i<end;i++){
int tmp = second;
second = Math.max(second, first + nums[i]);
first = tmp;
}

return second;
}
}