打家劫舍III
学习记录自代码随想录
要点:1.二叉树遍历顺序想到为后续遍历;
2.dp数组想到为长度为2,dp[0]代表不选该节点,dp[1]代表选该节点;
3.单次递归逻辑(递归公式)分偷父节点和不偷父节点两种情况,且不偷父节点时左右节点可以偷也可以不偷需要取较大值;
方法一:动态规划
/**
* 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:
// dp数组长度为2,dp[0]代表不选该节点的最大价值,dp[1]为选该节点的最大价值
vector<int> traversal(TreeNode* root){
if(root == nullptr) return {0, 0};
// 遍历顺序:后序遍历,左右中
vector<int> left = traversal(root->left);
vector<int> right = traversal(root->right);
// 不偷父节点, 左右节点可以偷也可以不偷
int val_1 = max(left[0], left[1]) + max(right[0], right[1]);
// 偷父节点
int val_2 = root->val + left[0] + right[0];
return {val_1, val_2};
}
int rob(TreeNode* root) {
vector<int> result = traversal(root);
return max(result[0], result[1]);
}
};
方法二:记忆递归
class Solution{
public:
unordered_map <TreeNode*, int> root_choose;
int rob(TreeNode* root){
if(root == nullptr) return 0;
if(root->left == nullptr && root->right == nullptr) return root->val;
if(root_choose[root]) return root_choose[root];
// 偷父节点
int val_1 = root->val;
if(root->left) val_1 += rob(root->left->left) + rob(root->left->right); // 跳过左节点到下一层
if(root->right) val_1 += rob(root->right->left) + rob(root->right->right); // 跳过右节点到下一层
// 不偷父节点
int val_2 = rob(root->left) + rob(root->right);
root_choose[root] = max(val_1, val_2);
return max(val_1, val_2);
}
};