
先从最简单的情况入手,找规律
我们从只有 1 间房、2 间房、3 间房的情况开始,一步步推导:
- 只有 1 间房
[a]:没得选,只能偷这间,最多偷a - 有 2 间房
[a, b]:不能同时偷,选钱多的那间,最多偷max(a, b) - 有 3 间房
[a, b, c]:- 选项 1:偷第 3 间房 → 不能偷第 2 间 → 最多偷
a + c - 选项 2:不偷第 3 间房 → 最多偷前 2 间的最大值
max(a, b) - 所以最多偷
max(a + c, max(a, b))
- 选项 1:偷第 3 间房 → 不能偷第 2 间 → 最多偷
发现规律了吗? 对于第 k 间房,你只有两个选择:偷 或者 不偷,取两个选择中钱更多的那个
动态规划核心思路(一句话讲透)
用 dp[i] 表示前 i 间房能偷到的最高金额,那么:
- 如果偷第 i 间房:第 i-1 间房不能偷 → 总金额 =
dp[i-2] + nums[i] - 如果不偷第 i 间房:总金额 =
dp[i-1](前 i-1 间房的最高金额)
所以状态转移方程:
dp[i] = max(dp[i-2] + nums[i], dp[i-1])
1. 处理边界情况
- 如果数组为空(没有房屋):返回 0
- 如果数组只有 1 个元素(只有 1 间房):返回这个元素的值
2. 初始化 dp 数组
dp[0] = nums[0]:只有第 0 间房,最多偷 nums 0dp[1] = max(nums[0], nums[1]):有两间房,偷钱多的那间
3. 遍历数组,计算 dp 数组
从第 2 间房开始(i=2),一直到最后一间房(i=n-1):
- 按照状态转移方程
dp[i] = max(dp[i-2] + nums[i], dp[i-1])计算每一个 dp i
4. 返回结果
dp[n-1] 就是前 n 间房能偷到的最高金额
cpp
class Solution {
public:
int rob(vector<int>& nums) {
//如果没有房 返回0
if(nums.empty()){
return 0;
}
//有一个房
int num = nums.size();
if(num == 1){
return nums[0];
}
//数组
vector<int> dp(num);
dp[0] = nums[0];
dp[1] = max(nums[0],nums[1]);
for(int i = 2;i<num;i++){
dp[i] =max(dp[i-2] + nums[i],dp[i-1]);
}
return dp[num-1];
}
};