打家劫舍
https://leetcode.cn/problems/house-robber/
注意要是i-1没偷,那么dp[i] = 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());
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.back();
}
};
打家劫舍Ⅱ
https://leetcode.cn/problems/house-robber-ii/
环形问题展开为线形,分析几种情况:
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());
vector<int> dp1(nums.size());
vector<int> dp2(nums.size());
//情况1 线性数组
// dp[0] = 0;
// dp[1] = nums[1];
// for (int i = 2; i < nums.size()-1; i++) {
// dp[i] = max(dp[i-2] + nums[i], dp[i-1]);
// }
//情况2 不偷尾
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-2] + nums[i], dp1[i-1]);
}
//情况3 不偷头
dp2[0] = 0;
dp2[1] = nums[1];
for (int i = 2; i < nums.size(); i++) {
dp2[i] = max(dp2[i-2] + nums[i], dp2[i-1]);
}
return max(dp1[nums.size()-2], dp2.back());
}
};
打家劫舍Ⅲ
https://leetcode.cn/problems/house-robber-iii/
大名鼎鼎的树形dp入门题,确实没做过的话完全想不到。。。
遍历树的节点的时候有两种情况,不偷自己和偷自己:robSelf[0]和robSelf[1],分别记录两种情况得到的最大金额。
注意偷自己的时候,两个孩子都属于不能偷的状态,所以robSelf[1] = self->val + left[0] + right[0];不偷自己的时候,两个孩子都能偷,所以可以偷他们俩最大值的和:robSelf[0] = max(left[0],left[1]) + max(right[0], right[1]);
class Solution {
public:
vector<int> robTree(TreeNode* root) {
vector<int> robSelf(2);
if (root == nullptr) return robSelf;
//后序遍历 左右中
vector<int> left = robTree(root->left);
vector<int> right = robTree(root->right);
//0不偷自己,偷俩孩子的和, 1偷自己,孩子都不能偷
robSelf[0] = max(left[0], left[1]) + max(right[0], right[1]);
robSelf[1] = root->val + left[0] + right[0];
return robSelf;
}
int rob(TreeNode* root) {
vector<int> robSelf = robTree(root);
return max(robSelf[0], robSelf[1]);
}
};