LeetCode-198 打家劫舍
考察内容:
数组、动态规划
题目描述:
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例:
输入[1, 2, 3, 1] 输出4 偷窃1号房屋(1元),由于不能连续偷窃,只能偷窃3号房屋(3元),最高金额为1+3=4元
输入[2, 7, 9, 3, 1] 输出12 偷窃1号房屋,再偷窃3号房屋,最后偷窃5号房屋,最高金额为2+9+1=12元
来源:力扣(LeetCode)
点我查看题目
解题思路:
题目描述首先要求我们不能进行连续的偷窃,所以先考虑特殊情况:如果只有一间房屋,那我们只能偷窃这一间房子;如果**只有两间房屋,**由于不能连续偷窃,所以我们只能选择其中一件进行偷窃,那我们肯定会选择金额最大的那间偷窃。
如果房屋数量大于两间,我们就先来考虑一共三间房屋,如果有三间房屋,我们可以偷盗的最大金额是什么呢?根据题目的要求,我们要么偷窃第一间和第三间房屋,要么只偷窃第二间房屋。所以当房屋数量为三的时候,能偷窃到的最大金额为1、3号房间之和与2号房间,两者中的最大值。
由此我们可以分析,对于超过两间房屋的情况,第n间房屋,只有两种选择:
- 偷第n间房屋,这样子的话就不可以偷窃第n-1间房屋了,此时能偷到的最大金额就是前n-2间房屋最大金额与第n间房屋的金额之和。
- 不偷第n间房屋,那么此时能够偷到的最大金额就是前n-1间房屋中的最大金额。
我们只需要在两种情况下选择最大的那个就满足了题目的要求。
首先创建一个dp数组,dp[i]代表在前i间房屋能偷到的最大金额,由上面的分析我们就可以写出状态转移方程:
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
C++解体代码及注释如下:
class solution{
public:
int rob(vector<int>& nums){
//两种特殊情况,房屋数量小于2的情况
if(nums.size() == 0){
return 0;
}
if(nums.size() == 1){
return nums[0];
}
vector<int>dp(nums.size());//创建dp数组,存放前i间房屋能偷窃到的最大金额。
dp[0] = nums[0],dp[1] = max(nums[0], nums[1]);//初始化dp数组的前两个值,因为从第三件房屋开始才用到状态转移方程。
//但是需要注意的是,dp[1]应该取前nums数组前两个元素中最大的那个。
//因为dp[1]表示的是前两间房屋能偷到的最大金额。
for(int i = 2; i < nums.size(); i++){
dp[i] = max(dp[i-2] + nums[i], dp[i-1]);//之前分析的状态转移方程
}
return dp[nums.size() - 1];//for循环走完后dp数组已经被填充满了.
//因为nums数组每个元素都非负,因此dp是一个严格递增的数组,只需要返回最后的那个元素,就是所有房屋能偷到的最大金额。
}
};