二叉树的最近公共祖先

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

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

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

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

说明:

  • 所有节点的值都是唯一的。
  • p、q 为不同节点且均存在于给定的二叉树中。

思路一:使用栈来判断路径
这个思路是我自己想的,我竟然可以自己做出这么复杂的题目了,哈哈哈。
首先利用递归,找到目标节点,然后将它入栈里,再把它的父节点入栈……一直到根节点。两个节点分别对应两个栈,然后再分别出栈,最后一个相等的节点就是最近公共祖先啦。

  • 时间复杂度:不会算
  • 空间复杂度:O(n)
class Solution {
    Stack<TreeNode> stack1;
    Stack<TreeNode> stack2;
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        stack1 = new Stack<TreeNode>();
        stack2 = new Stack<TreeNode>();
        findNode(root,p,stack1);
        findNode(root,q,stack2);
        TreeNode res = null;
        while(!stack1.empty() && !stack2.empty()){
            if(stack1.peek()==stack2.peek()){
                res = stack1.pop();
                stack2.pop();
            }else{
                break;
            }
        }
        return res;
    }
    //判断有没有找到对应节点
    public boolean findNode(TreeNode node,TreeNode target,Stack<TreeNode> stack){
        if(node == target){
            stack.push(node);	//找到就入栈
            return true;
        }
        if(node==null)  return false;
        if(findNode(node.left,target,stack) || findNode(node.right,target,stack)){
            stack.push(node);
            return true;
        }
        return false;
    }
}

思路二:
这个思路和我差不多,都是用递归加一个boolean判断。不过这个就精巧很多,不需要判断路径,只要一个节点的左右子节点返回都为true,那么这个节点就是最近公共祖先。

class Solution {
    TreeNode res;
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        findNode(root,p,q); 
        return res;
    }
    //判断有没有找到对应节点
    public boolean findNode(TreeNode node,TreeNode p,TreeNode q){
        if(node==null) return false;
        if(node==p || node==q)  {//这里只要找到相等就把它当作结果,如果此节点恰好是最近公共祖先,那就正好;如果不是,后面会替换掉的。
            res = node;
            return true;
        }
        boolean leftFind = findNode(node.left,p,q);
        boolean rightFind = findNode(node.right,p,q);
        if(leftFind && rightFind){
            res = node;
            return true;
        }
        if(leftFind || rightFind){
            return true;
        }
        return false;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值