【198.打家劫舍】
当前下标的房屋可以偷到的最大的金钱数依赖于前一个房屋能偷到的最大金钱数和前前一个的最大金钱数。所以是一个动态规划的问题。
dp数组的定义:下标为i的房屋可以偷到的最大金钱数量为多少
dp数组的初始化:dp[0] = nums[0] dp[1] = max(nums[0],nums[1])
递推公式:dp[i] = max(dp[i-2]+nums[i], dp[i-1]);偷当前和不偷当前哪一个最大
遍历顺序:从前往后遍历
举例推导
代码如下:
class Solution {
public:
int rob(vector<int>& nums) {
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++){
dp[i] = max(dp[i-2]+nums[i], dp[i-1]);
}
return dp[nums.size() - 1];
}
};
【213. 打家劫舍 II】
这道题目将之前的数组构成了一个环。这样就需要考虑两种情况,第一种是考虑偷第一家、不偷最后一家的情况,第二种是考虑不偷第一家、偷最后一家的情况。
具体偷的逻辑还是和198.打家劫舍一样。
最后比较两种情况哪个偷盗的金额更大。
具体代码如下:
class Solution {
public:
int robRange(vector<int>& nums, int start, int end){
if(start == end) return nums[start]; //当只有一个元素的时候
vector<int>dp(nums.size());
dp[start] = nums[start];
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];
}
int rob(vector<int>& nums) {
if(nums.size() == 0)return 0; //当数组长度为0的时候
if(nums.size() == 1)return nums[0]; //当数组长度为1的时候
int res1 = robRange(nums, 0, nums.size()-2); //第一种情况
int res2 = robRange(nums, 1, nums.size()-1); //第二种情况
return max(res1, res2);
}
};
在写这个代码的过程中,遇到了一个bug。、
dp数组的长度应该为nums.size(),而不能是nums.size()-1。因为第二种情况下,会访问到nums.size()-1这个下标。如果数组长度-1了,就会出现访问错误。
其次dp数组的初始化需要从start下标开始,而不是从0开始了。