😄213.打家劫舍II
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
思路
基本思想
相比于
198题
,本题只是多了一个限制条件,头尾也变成邻居,也就是第一个房屋被偷,最后一个房屋就不能被偷,每偷一个房间,至少隔一个房间才能继续偷
影响解题的因素就是头尾两个房间连起来了,所以我们将其分开,分情况讨论:
- 去掉头部元素
- 去掉尾部元素
去掉之后可以将其当成198题进行统计,由于统计的过程中情况1有可能不选择尾部元素,情况2有可能不选择头部元素,所以同时不选择头尾的元素这种情况已经被包含了,剩下的就是198题的逻辑
执行流程
按照情况分开,分别对情况1和情况2进行统计,最终返回大的结果
- 初始化dp数组
- 集体处理只有一个和两个元素的情况
- 按照递推公式进行统计
- 返回最终的结果
代码
根据以上分析,得出以下代码:
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
| class Solution {
public:
int rob(vector<int>& nums) {
//这两句不能忘掉,否则会出现下标越界的情况
if (nums.size() == 1) return nums[0];
if (nums.size() == 2) return max(nums[0],nums[1]);
//到这里至少三个元素
int result1 = robRange(nums, 0, nums.size() - 1);
int result2 = robRange(nums, 1, nums.size() );
return max(result1, result2);
}
// 198.打家劫舍的逻辑
int robRange(vector<int>& nums, int start, int end) {
vector<int> dp(nums.size());
dp[start] = nums[start];
//如果start=1时,这句初始化应该有问题
//因为dp[i]代表的是下标为[o,start]的房屋中能够获取到的最大金额
//而start=1时,dp[start+1]代表房屋的范围为[0,2]一共三个房屋
dp[start + 1] = max(nums[start], nums[start + 1]);
for (int i = start + 2; i < end; i++) {
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
}
return dp[end-1];
}
};
|
总结
主要是将头尾相接的问题分情况讨论,注意同时去掉头尾的情况已经包含在了情况1和情况2中
本题中dp数组按照下标进行更新,而不是按照元素在第几进行更新是因为去掉尾部时,元素以0开头,去掉头部时元素以1开头,开头的元素下标不固定,所以只能按照下标去访问
按照下标去访问,可以将不同区间的元素统一处理