865. 具有所有最深节点的最小子树

本文对比了三种高效解决最深叶节点最近公共祖先问题的算法思路,包括深度优先遍历结合最大深度计算、一次递归记录节点深度与地址,以及官方推荐的仅遍历一次记录节点距离的方法。详细解析了每种方法的实现细节和优势。

与《1123. 最深叶节点的最近公共祖先》题相同。

求最深叶节点的lca就是求具有所有最深节点的最小子树。

思路1:一遍dfs求最大深度,再来一遍dfs求这些深度最大的点的lca

class Solution {
public:
    int getDepth(TreeNode* root)
    {
        if (root)
        {
            int left = getDepth(root->left);
            int right = getDepth(root->right);
            return max(left, right)+1;
        }
        return -1;
    }

    TreeNode* lca(TreeNode* root, int depth, int curdepth)
    {
        if (curdepth == depth || root == NULL)
            return root;
        
        TreeNode* left = lca(root->left, depth, curdepth+1);
        TreeNode* right = lca(root->right, depth, curdepth+1);

        if (left && right)
            return root;
        else if (left)
            return left;
        else
            return right;
    }

    TreeNode* lcaDeepestLeaves(TreeNode* root) {
        int depth = getDepth(root);
        TreeNode* res = lca(root, depth, 0);
        return res;
    }
};

思路2:只做一遍递归,同时记录节点地址和节点的深度。如果一个节点的左右子树中包含最深节点的深度不一样,返回拥有更大深度节点的子树的根节点和最大深度;如果深度一样,则返回该节点,以及左右子树中深度最大节点的深度

class Solution {
public:
    pair<TreeNode*, int> dfs(pair<TreeNode*, int> root)
    {
        if (root.first == NULL)
            return make_pair(nullptr, 0);
        
        pair<TreeNode*, int> left = dfs(make_pair(root.first->left, root.second+1));
        pair<TreeNode*, int> right = dfs(make_pair(root.first->right, root.second+1));

        if (left.second > right.second) return left;
        else if (left.second < right.second) return right;
        else return make_pair(root.first, !left.first ? root.second : left.second);
    }
    
    TreeNode* subtreeWithAllDeepest(TreeNode* root) {
        return dfs(make_pair(root, 0)).first;
    }
};

思路3(官方解法):只做一遍递归,同时记录节点地址和节点到最深节点的距离(节点的高度)。如果一个节点的左右子树高度不同,返回高度更大子树的根节点和该节点的高度;如果高度一样,则返回该节点和该节点的高度。

给定一个根为 root 的二叉树,每个节点的深度是 该节点到根的最短距离 。 获得包含原始树中所有 最深节点最小子树,并输出该子树 。 如果一个节点在 整个树 的任意节点之间具有最大的深度,则该节点最深的 。 一个节点的 子树 是该节点加上它的所有后代的集合。 示例 1: 输入: 11 3 5 1 6 2 0 8 null null 7 4 输出: 2 7 4 解释: 我们返回值为 2 的节点,在图中用黄色标记。 在图中用蓝色标记的是树的最深节点。 注意,节点 5、3 和 2 包含树中最深节点,但节点 2 的子树最小,因此我们返回它。 示例 2: 输入: 1 1 输出: 1 解释:根节点是树中最深节点。 可以使用以下函数输入输出: struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode() : val(0), left(NULL), right(NULL){} TreeNode(int x) : val(x), left(NULL), right(NULL) {} TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} }; TreeNode* inputTree() { int n,count=0; char item[100]; cin>>n; if (n==0) return NULL; cin>>item; TreeNode* root = new TreeNode(atoi(item)); count++; queue<TreeNode*> nodeQueue; nodeQueue.push(root); while (count<n) { TreeNode* node = nodeQueue.front(); nodeQueue.pop(); cin>>item; count++; if (strcmp(item,"null")!=0) { int leftNumber = atoi(item); node->left = new TreeNode(leftNumber); nodeQueue.push(node->left); } if (count==n) break; cin>>item; count++; if (strcmp(item,"null")!=0) { int rightNumber = atoi(item); node->right = new TreeNode(rightNumber); nodeQueue.push(node->right); } } return root; } void levelOrder(TreeNode* root){ if (root == nullptr) { return ; } queue<TreeNode*> Q; Q.push(root); while (!Q.empty()) { int size = Q.size(); for(int i = 0; i < size; i++) { TreeNode* node = Q.front(); Q.pop(); if(node){ cout<<node->val<<" "; }else{ cout<<"null "; continue; } if(!(!node->left&&!node->right)){ Q.push(node->left); Q.push(node->right); } } } } 输入说明 首先输入结点的数目n(注意,这里的结点包括题中的null空结点) 然后输入n个结点的数据,需要填充为空的结点,输入null。 提示: 树中节点的数量在 [1, 500] 范围内。 0 <= Node.val <= 500 每个节点的值都是 独一无二 的。 输出说明 输出结果,需要填充为空的结点,输出null,每个数据的后面跟一个空格。 输入范例 5 0 1 3 null 2 输出范例 2
最新发布
06-04
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值