思路分析:
- 使用两个二维数组dp1和dp2,分别表示考虑第一家到倒数第二家和第二家到最后一家的情况。
- 动态规划的状态定义:
- dp[i][0]表示不偷第i家时的最大金额。
- dp[i][1]表示偷第i家时的最大金额。
- 初始化第一家和第二家的情况,并通过遍历计算每家不偷和偷的最大金额。
- 最后返回两组动态规划的最大金额中的较大值。
※
※※※ 为什么分别考虑第一家到倒数第二家和第二家到最后一家的情况?
※
具体原因如下:
-
第一家到倒数第二家的情况(dp1数组):
- 不偷第一家(dp1[i][0]):可以考虑偷取从第二家到倒数第二家的任意一家,问题规模减小,因此用动态规划记录最大金额。
- 偷第一家(dp1[i][1]):由于偷了第一家,所以不能偷第二家,可以考虑偷取从第三家到倒数第二家的任意一家,问题规模减小,同样用动态规划记录最大金额。
-
第二家到最后一家的情况(dp2数组):
- 不偷第二家(dp2[i][0]):可以考虑偷取从第三家到最后一家的任意一家,问题规模减小,同样用动态规划记录最大金额。
- 偷第二家(dp2[i][1]):由于偷了第二家,所以不能偷第一家,可以考虑偷取从第三家到最后一家的任意一家,问题规模减小,同样用动态规划记录最大金额。
这样分别考虑两种情况,最终比较两种情况的最大金额,选择其中较大的一个作为整体的最大金额。这种分别考虑两个子问题的方式有助于避免考虑相邻两家的问题,确保最终得到的最大金额是不相邻的房屋所能获得的最大值。
class Solution {
public:
int rob(vector<int>& nums) {
// 创建两个二维数组dp1和dp2,用于动态规划
// dp1用于考虑第一家到倒数第二家的情况,dp2用于考虑第二家到最后一家的情况
vector<vector<int>> dp1(nums.size(), vector<int>(2, 0));
vector<vector<int>> dp2(nums.size(), vector<int>(2, 0));
int i;
// 如果只有一家,直接返回该家的金额
if (nums.size() == 1)
return nums[0];
// 初始化第一组动态规划数组dp1的第一家情况
dp1[0][0] = 0; // 不偷第一家
dp1[0][1] = nums[0]; // 偷第一家
// 遍历考虑第一家到倒数第二家的情况
for (i = 1; i < nums.size() - 1; i++) {
dp1[i][0] = max(dp1[i-1][0], dp1[i-1][1]); // 不偷当前家,取前一家的最大金额
dp1[i][1] = dp1[i-1][0] + nums[i]; // 偷当前家,加上前一家不偷的最大金额
}
// 初始化第二组动态规划数组dp2的第二家情况
dp2[1][0] = 0; // 不偷第二家
dp2[1][1] = nums[1]; // 偷第二家
// 遍历考虑第二家到最后一家的情况
for (i = 2; i < nums.size(); i++) {
dp2[i][0] = max(dp2[i-1][0], dp2[i-1][1]); // 不偷当前家,取前一家的最大金额
dp2[i][1] = dp2[i-1][0] + nums[i]; // 偷当前家,加上前一家不偷的最大金额
}
// 返回两组动态规划的最大金额
return max(max(dp1[nums.size()-2][0], dp1[nums.size()-2][1]), max(dp2[nums.size()-1][0], dp2[nums.size()-1][1]));
}
};