198.打家劫舍
思路
- 数组以及下标含义
dp[j]:当偷到第j家时所能获得的最多的金钱 - 递推公式
dp[j] = max(dp[j - 1], dp[j - 2] + nums[i])
当偷到第j家时,如果偷这家,那么就不能偷前一家,所能得到的最大金额为dp[j - 2] + prices[i]
如果不偷这家,获得的金额与偷到第j-1家相等,所获得的最大金额为dp[j-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-1], dp[i-2] + nums[i]);
}
return dp[nums.size()-1];
}
};
复杂度分析
- 时间复杂度:O(n),n为数组的长度
- 空间复杂度:O(n)
213.打家劫舍II
思路
这道题与上一道题的区别在于不能同时偷第一家和最后一家,那么只能将两种情况分开讨论。
实现
点击查看代码
class Solution {
public:
int rob(vector<int>& nums) {
if(nums.size() == 1) return nums[0];
else if(nums.size() == 2) return max(nums[0], nums[1]);
int result1 = myRob(nums, 0, nums.size() - 2);
int result2 = myRob(nums, 1, nums.size() - 1);
return max(result1, result2);
}
int myRob(vector<int>& nums, int start, int end) {
vector<int> dp(nums.size(), 0);
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 - 1], dp[i - 2] + nums[i]);
}
return dp[end];
}
};
复杂度分析
- 时间复杂度:O(n)
- 空间复杂度:O(n)
337.打家劫舍III
思路
实现
点击查看代码
class Solution {
public:
int rob(TreeNode* root) {
vector<int> result = robTree(root);
return max(result[0], result[1]);
}
vector<int> robTree(TreeNode* root) {
if(root == nullptr) return {0, 0};
vector<int> left = robTree(root->left);
vector<int> right = robTree(root->right);
int val1 = root->val + left[0] + right[0];
int val2 = max(left[0],left[1]) + max(right[0], right[1]);
return {val2, val1};
}
};
复杂度分析
- 时间复杂度:O(n)
- 空间复杂度:O(logn)