236.二叉树的最近公共祖先

236. 二叉树的最近公共祖先 - 力扣(LeetCode) (leetcode-cn.com)

 

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

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

示例 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 。因为根据定义最近公共祖先节点可以为节点本身。
示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1
 

提示:

树中节点数目在范围 [2, 105] 内。
-109 <= Node.val <= 109
所有 Node.val 互不相同 。
p != q
p 和 q 均存在于给定的二叉树中。

解法一

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null){
            return null;
        }
        if(p == root || q == root){
            return root;
        }
//上面两个if是去判断返回值的,接下来去不断递归,每递归一次去判断是不是有返回值(否则就是不满足上面两种情况,那么继续去递归)
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);
//通过下面的图我们知道,基本分成三种情况,但你用代码去处理很简单。第一种情况的时候,在p和q分别在根的左右子树上,我们去递归左子树找到一个就去返回,然后去递归右子树找到了了就返回,记录下这两个返回值,当这两个返回值不为null时,就说明是对称的。
//第二种是p/q都在左子树的时候,此时,你第一次递归就返回左子树然后去递归右子树,最后记录下的发现
左子树最终递归的不是null,而右子树是null,说明两个本来都是在root的左子树上,而且一个还是另一个的祖先。
//第三种也是一样的,左子树递归为null,然后去右子树递归发现找到了,就返回,下面的代码一判断就知道返回的那个肯定就是本身和另一个的祖先
        if(left == null){
            return right;
        }
        if(right == null){
            return left;
        }
        //这里表示的是left和right都不为空
        return root;
    }
}

​

 解法二:链表求交点法

1、用两个栈去存储这两个节点的路径的结点

2、求栈的大小

3、让栈中多的元素 出差值步

4、开始出栈、直到栈顶元素相同时知道了最近祖先

那么此时最大的困难就是如何去找到存储的路径(回溯的思想),深度优先遍历嘛

直接上代码:看不懂再去看视频讲解

class Solution {
    boolean getpath(TreeNode root,TreeNode node,Stack<TreeNode> stack){
        if(root == null || node == null){
            return false;
        }
        stack.push(root);
        if(root == node){
            return true;
        }
        boolean flg = getpath(root.left,node,stack);
        if(flg == true ){
            return true;
        }
        flg = getpath(root.right,node,stack);
        if(flg == true ){
            return true;
        }
        stack.pop();
        return false;
    }
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        Stack<TreeNode> stack1 = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();
        getpath(root,p,stack1);
        getpath(root,q,stack2);
        int size1 = stack1.size();
        int size2 = stack2.size();
        int size = size1-size2;
        if(size>0){
            while(size != 0){
                stack1.pop();
                size--;
            }
            while(!stack1.isEmpty() && !stack2.isEmpty()){
                if(stack1.peek() == stack2.peek()){
                    return stack1.pop();
                }else{
                    stack1.pop();
                    stack2.pop();
                }
            }
        }else{
            size = size2-size1;
            while(size != 0){
                stack2.pop();
                size--;
            }
            while(!stack1.isEmpty() && !stack2.isEmpty()){
                if(stack1.peek() == stack2.peek()){
                    return stack1.pop();
                }else{
                    stack1.pop();
                    stack2.pop();
                }
            }
        }
        return null;

    }
}

 

参与评论 您还未登录,请先 登录 后发表或查看评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:数字20 设计师:CSDN官方博客 返回首页

打赏作者

忱叁

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值