和斐波那契数列,还有跳楼梯很类似,都是根据前面的两项变化
AC代码:
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.size() == 1) {
return nums[0];
}
int n = nums.size();
// dp数组定义:第i间房能获取的最大利润
vector<int> dp(n + 1);
dp[0] = nums[0];
dp[1] = max(dp[0], nums[1]);
for (int i = 2; i < n; ++i) {
dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
}
return dp[n - 1];
}
};
不能打劫相邻的屋子且所有屋子构成一个环,意味着第0位的屋子和最后一位的屋子相邻; 我们可以将问题分成两份:从第0位的屋子开始和从第1位的屋子开始,这样问题就又变为和198. 打家劫舍想同的问题了,只是从第0位开始的那一份结束在第n-2位的屋子,而从第1位开始的那一份结束于第n-1位的屋子,这样分我们就不用再处理环了
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
if (n == 1) {
return nums[0];
} else if (n == 2) {
return max(nums[0], nums[1]);
}
vector<int> beginFromZero(n);
vector<int> beginFromOne(n);
beginFromZero[0] = nums[0];
beginFromZero[1] = max(beginFromZero[0], nums[1]);
for (int i = 2; i < n - 1; ++i) {
beginFromZero[i] =
max(beginFromZero[i - 1], beginFromZero[i - 2] + nums[i]);
}
beginFromOne[1] = nums[1];
beginFromOne[2] = max(beginFromOne[1], nums[2]);
for (int i = 3; i < n; ++i) {
beginFromOne[i] =
max(beginFromOne[i - 1], beginFromOne[i - 2] + nums[i]);
}
return max(beginFromZero[n - 2], beginFromOne[n - 1]);
}
};
递归+记忆化搜索:每个节点都有两种状态:打劫或是不打劫;如果打劫当前节点,那么要求前一个节点不能被打劫,且后一个节点也不能被打劫了;如果不打劫当前节点,那么前一个节点没有要求,后一个节点既可以打劫也可以不打劫。 用两个哈希表分别记录每个节点打劫或不打劫所能得到的最大金额
树形dp:用一个vector来保存状态,从底到顶返回,避免每种状态都去递归计算一次
代码如下:
class Solution {
public:
unordered_map<TreeNode*, int> robOnNode;
unordered_map<TreeNode*, int> noRobOnNode;
int rob(TreeNode* root) {
if (root == nullptr) {
return 0;
}
return max(GetAnswer(root, true), GetAnswer(root, false));
}
int GetAnswer(TreeNode* root, bool canRob) {
if (root == nullptr) {
return 0;
}
int sum_rob = 0;
int sum_no_rob = 0;
if (canRob) {
if (robOnNode.find(root) == robOnNode.end()) {
sum_rob += root->val;
sum_rob += GetAnswer(root->left, false);
sum_rob += GetAnswer(root->right, false);
robOnNode.emplace(root, sum_rob);
} else {
sum_rob = robOnNode[root];
}
}
if (noRobOnNode.find(root) == noRobOnNode.end()) {
sum_no_rob += GetAnswer(root->left, true);
sum_no_rob += GetAnswer(root->right, true);
noRobOnNode.emplace(root, sum_no_rob);
} else {
sum_no_rob = noRobOnNode[root];
}
return max(sum_no_rob, sum_rob);
}
};
//树形dp
class Solution {
public:
int rob(TreeNode* root) {
vector<int> result = robTree(root);
return max(result[0], result[1]);
}
// 长度为2的数组,0:不偷,1:偷
vector<int> robTree(TreeNode* cur) {
if (cur == NULL) return vector<int>{0, 0};
vector<int> left = robTree(cur->left);
vector<int> right = robTree(cur->right);
// 偷cur,那么就不能偷左右节点。
int val1 = cur->val + left[0] + right[0];
// 不偷cur,那么可以偷也可以不偷左右节点,则取较大的情况
int val2 = max(left[0], left[1]) + max(right[0], right[1]);
return {val2, val1};
}
};