213 打家劫舍 II

本文最后更新于:2021年1月30日 上午

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

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

示例 1:

1
2
3
输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

示例 2:

1
2
3
4
输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4

示例 3:

1
2
输入:nums = [0]
输出:0

提示:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 1000

Solution

参考:《算法小抄》2.18

  • 环形数组
  • 首先,首尾房间不能同时被抢,那么只可能有三种不同情况:要么都不被抢;要么第一间房子被抢最后一间不抢;要么最后一间房子被抢第一间不抢。
  • 只要比较情况二和情况三就行,因为这两种情况对于房子的选择余地比情况一大呀,最优决策结果肯定不会小。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# @lc code=start
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums)==1:
return nums[0]
def subRob(nums):
cur, pre1, pre2 = 0,0,0
for num in nums:
cur = max(pre1, pre2+num)
pre2 = pre1
pre1 = cur
return cur
return max(subRob(nums[:-1]), subRob(nums[1:]))
# @lc code=end

cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// @lc code=start
class Solution {
private:
int go(const vector<int>& nums, int index, int l, int r){
int pre1 = 0, pre2=0, cur = 0;
for(int i=l; i<r; ++i){
cur = max(nums[i]+pre2, pre1);
pre2 = pre1;
pre1 = cur;
}
return cur;
}

public:
int rob(vector<int>& nums) {
int n = nums.size();
if(n==0) return 0;
if(n==1) return nums[0];

int res1 = go(nums, 0, 0, n-1);
int res2 = go(nums, 1, 1, n);
return max(res1, res2);
}
};
// @lc code=end

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!