2020-05-10 LeetCode 236 二叉树的最近公共祖先

题目:

​​​  给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

​​​  百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

​​​  例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]

img

示例1:

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。

示例2

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。

​​​  这道题做的我一波三折,折腾了一个上午。看到题目后受前几天做题的影响,就想用先中后序遍历之类的方式,思考了一阵后想到的解决方案是利用层序遍历获得每个节点的下标,然后通过下标来获得树节点往上遍历的路径(除2就完事了),寻找到第一个交叉点就好了。最开始想着时间复杂度是O(N),应该还能行(这里没想到应该只考虑非null节点数时间复杂度是真的蠢,也是树的题目做的太少了),然后折腾了一个上午写好了层序遍历(甚至把另外一道层序遍历题做了)和这个题的题解,结果测试的时候TLE了,看着测试用例里边满屏的null陷入了沉思。

​​​  心态有点小蹦,后面想既然这样的话修改应该是只用遍历非空节点,获得路径的思想没有问题,就是遍历的方式错了。突然,脑力里边灵光乍现Tarjan ,我以前不是在书上看过这种题型吗??还折腾了这么久,自动浮现coding一定要笑.jpg。

​​​  到这已经没心情复现了,稿纸上写了下伪代码就去看题解了,其实官方题解第二个就是Tarjan ,主要思想也就进行dfs存储路径然后寻找最近的交叉点,详情可见https://www.cnblogs.com/JVxie/p/4854719.html,官方实现的代码也挺简洁的,只是没想到Tarjan会比递归的方式更慢

class Solution {
public:
    unordered_map<int, TreeNode*> fa;
    unordered_map<int, bool> vis;
    void dfs(TreeNode* root){
        if (root->left != nullptr) {
            fa[root->left->val] = root;
            dfs(root->left);
        }
        if (root->right != nullptr) {
            fa[root->right->val] = root;
            dfs(root->right);
        }
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        fa[root->val] = nullptr;
        dfs(root);
        while (p != nullptr) {
            vis[p->val] = true;
            p = fa[p->val];
        }
        while (q != nullptr) {
            if (vis[q->val]) return q;
            q = fa[q->val];
        }
        return nullptr;
    }
};

执行结果

在这里插入图片描述

​​​  递归最主要就是就是找到相关规律来确定return,我一开始嫌弃递归慢所以都没往这方面想,果然还是太菜了。规律主要是左右都有p或者q(一边一个,本身也可以算做左右),那就是最终返回的结果;左没便在右,右没便在左。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) {
            return root;
        }
        if (root == p || root == q) {
            return root;
        }
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if (left != null && right != null) {
            return root;
        } else if (left != null) {
            return left;
        } else if (right != null) {
            return right;
        }
        return null;
    }
}

执行结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值