leetcode:198. 打家劫舍 - 力扣(LeetCode)
题目
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
- 示例 1:
- 输入:[1,2,3,1]
- 输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 偷窃到的最高金额 = 1 + 3 = 4 。
- 示例 2:
- 输入:[2,7,9,3,1]
- 输出:12 解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。 偷窃到的最高金额 = 2 + 9 + 1 = 12 。
提示:
- 0 <= nums.length <= 100
- 0 <= nums[i] <= 400
思路
动规五部曲
(1)dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]。
(2)决定dp[i]的因素就是第i房间偷还是不偷。
如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i]
如果不偷第i房间,那么dp[i] = dp[i - 1],即考虑i-1房,(注意这里是考虑,并不是一定要偷i-1房,这是很多同学容易混淆的点)
然后dp[i]取最大值,即dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
(3)递推公式有i-2和i-1,所以初始化应该考虑dp[0]和dp[1]。
dp[0]=nums[0]
dp[1]=max(nums[0],nums[1])
1后面的,初始化0就行了,反正后面也是递推得到的。
(4)每次推导要用到前面的两个状态,所以是从前往后推导的,i=2开始往后遍历即可。
代码如下:
#include <iostream>
#include <vector>
using namespace std;
class Solution
{
public:
/**
* 解决打家劫舍问题,返回沿街房屋最大可以偷取的金额
* @param nums 包含每个房屋金额的整数数组
* @return 返回沿街房屋最大可以偷取的金额
*/
int rob(vector<int> &nums)
{
// 如果没有房屋,返回0
if (nums.size() == 0)
return 0;
// 如果只有一个房屋,返回该房屋的金额
if (nums.size() == 1)
return nums[0];
// 初始化动态规划数组,用于存储到每个房屋为止的最大偷取金额
vector<int> dp(nums.size(), 0);
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
// 从第三个房屋开始,更新动态规划数组
for (int i = 2; i < nums.size(); i++)
{
// 对于当前房屋i,计算两种情况下的最大值:
// 1. 不偷当前房屋,金额为到上一个房屋i-1为止的最大金额
// 2. 偷当前房屋,金额为到i-2房屋为止的最大金额加上当前房屋的金额
dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
}
// 返回最后一个房屋处的最大偷取金额
return dp[nums.size() - 1];
}
};
(5)举例推导:
总结
比较简单