198 打家劫舍
题目链接:198
思路:dp[i]
代表考虑偷[0,i]
时能偷到的最大金额,则有两种情况:
- 考虑不偷
i
的情况,则最大的金额一定是偷[0,i-1]
时最大的金额dp[i-1]
; - 考虑偷
i
,即i-1
不能偷,剩下的只能从[0,i-2]
偷,因此最大金额dp[i-2]+nums[i]
。 - 二者取大,得递推
dp[i]=max(dp[i-1], dp[i-2])
。
代码:
class Solution {
public:
int rob(vector<int>& nums) {
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.back();
}
};
213 打家劫舍 II
题目链接:213
思路:由于第一个房子和最后一个房子不能同时偷,因此可以分开考虑,先考虑不偷第一个房子的情况,再考虑不偷最后一个房子的情况,再比较二者取大的。
代码:
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.size() == 1) return nums[0];
if (nums.size() == 2) return max(nums[0], nums[1]);
vector<int> dp1(nums.size()-1, 0);
vector<int> dp2(nums.size()-1, 0);
dp1[0] = nums[0];
dp1[1] = max(nums[0], nums[1]);
for (int i=2; i<nums.size()-1; i++) {
dp1[i] = max(dp1[i-1], dp1[i-2]+nums[i]);
}
dp2[0] = nums[1];
dp2[1] = max(nums[1], nums[2]);
for (int i=2; i<nums.size()-1; i++) {
dp2[i] = max(dp2[i-1], dp2[i-2]+nums[i+1]);
}
return max(dp1.back(), dp2.back());
}
};
337 打家劫舍 III
题目链接:337
思路:后序遍历二叉树,递归返回值为偷或不偷当前节点时子树的最大金额。对于每个节点,若偷当前节点,则金额为cur->val + left[0] + right[0]
;若不偷,则金额为max(left[0], left[1]) + max(right[0], right[1])
。
代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
//{不偷,偷}
vector<int> recurse(TreeNode* cur) {
if (!cur) return {0, 0};
vector<int> left = recurse(cur->left);
vector<int> right = recurse(cur->right);
int steal_cur = cur->val + left[0] + right[0];
int not_steal_cur = max(left[0], left[1]) + max(right[0], right[1]);
return {not_steal_cur, steal_cur};
}
int rob(TreeNode* root) {
vector<int> result = recurse(root);
return max(result[0], result[1]);
}
};