小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root
。
除了 root
之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。
给定二叉树的 root
。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。
/**
* 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) {}
* };
*/
算法:
和之前做过的Leetcode 198. 打家劫舍类似,选了当前结点就不能选与之相连的结点了。
这里我们分成两种情况,当前节点 选 或者 不选 。需要考虑几个点,结点是否为空?如果选了当前结点 node ,那就不能选他的 两个儿子结点(node -> left , node -> right)。
在每次递归时,我们要 return 两种情况,选 或者 不选。即 1、选当前节点 2、不选当前节点,取左右儿子的最大值。
时间复杂度:O(n) ,其中 n 为二叉树的节点个数。每个节点都会递归恰好一次。
空间复杂度:O(n) 。最坏情况下,二叉树是一条链,递归需要 O(n) 的栈空间。
代码:
class Solution {
pair<int,int>dfs(TreeNode *node){
if(!node) return {0,0};// 递归边界,没有节点,怎么选都是 0
auto [l_rob,l_not_rob] = dfs(node->left); // 递归左子树
auto [r_rob,r_not_rob] = dfs(node->right); // 递归右子树
int rob = l_not_rob + r_not_rob + node->val; // 选
int not_rob = max(l_rob,l_not_rob) + max(r_rob,r_not_rob); // 不选
return {rob,not_rob};
}
public:
int rob(TreeNode* root) {
auto[root_rob,root_not_rob] = dfs(root);
return max(root_rob,root_not_rob); // 根节点选或不选的最大值
}
};