二叉树的最近公共祖先

16 篇文章 0 订阅

题目描述:

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

样例:

在这里插入图片描述
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5

分析:

法1:分别找出根节点到两个节点的路径,则最后一个公共节点就是最低公共祖先。

  • 利用一个栈来存储到节点的路径,栈中的最后一个节点肯定是目标节点。
  • 如果某一个节点其左子树和右子树都不存在目标结点,则将该节点从栈中pop,继续遍历该节点的兄弟节点
  • 然后从栈中的第一节点开始遍历,当对应节点不相同时结束遍历,最后一个相同的节点即为公共祖先,即当前结束节点的上一个节点。

法2:

  • 如果查询节点分别位于该节点的左子树和右子树中,则祖先肯定是该节点;
  • 如果在该节点的左子树中没有找到查询节点,则一定都位于该节点的右子树中,最低公共祖先一定位于右子树中。
  • 如果在该节点的右子树中没有找到查询节点,则一定都位于该节点的左子树中,最低公共祖先一定位于左子树中。
 public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null)
        	return null;
        if(p==root&&q!=null||q==root&&p!=null) {
        	return root;
        }
        Stack<TreeNode> stack1=new Stack<>();
        findpath(root,p,stack1,new TreeNode(0));
        Stack<TreeNode> stack2=new Stack<>();
        findpath(root,q,stack2,new TreeNode(0));
        TreeNode common=null;
        for(int i=0;i<Math.min(stack1.size(), stack2.size());i++) {
        	if(stack1.get(i)==stack2.get(i))
        		common=stack1.get(i);
            else
                break;
        }
   
        return common;
    }
	
	public void findpath(TreeNode root,TreeNode search,Stack<TreeNode> stack,TreeNode flag) {
		if(root==null||flag.val==1)//保证了栈中最后一个节点肯定是search
			return;
		stack.push(root);
		if(root.val==search.val) {
			flag.val =1;
			return;
		}
		findpath(root.left,search,stack,flag);
		findpath(root.right,search,stack,flag);
		if(flag.val!=1) {//说明以该节点为根节点的子树中不存在查找节点  !!!!
			stack.pop();
		}
	}
	public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) {
		if(root==null)
			return null;
		if(root==p||root==q) {
			return root;
		}
		TreeNode left=lowestCommonAncestor2(root.left,p,q);
		TreeNode right=lowestCommonAncestor2(root.right,p,q);
		if(left!=null&&right!=null)
			return root;//查询节点分别位于root节点的左右子树中
		if(left==null)//查询节点均位于root节点的右子树中
			return right;
		if(right==null)//查询节点位于root节点的左子树中
			return left;
		return null;
			
	}

相关题目:
二叉搜索树的最近公共祖先。

  • 将查询节点的值和根节点的值进行比较,如果均大于根节点的值,则最低公共祖先一定位于右子树;如果均小于根节点的值,则最低公共祖先一定位于左子树;如果一个大于一个小于,则最低公共祖先为根节点。

普通树的最近公共祖先。

  • 如果有指向父节点的指针,则每个叶节点到根节点都看以看做一个链表,因此转换为寻找两个链表的第一个公共节点。
    在这里插入图片描述

  • 如果没有指向父节点的指针,则利用两个栈分别保存从根节点到查找节点的路径,在保存的过程中如果某个节点的左子树和右子树均没有该节点则将该节点从栈中pop,确保栈中的最后一个节点是查找的节点。

  • 然后从栈中的第一节点开始遍历,当对应节点不相同时结束遍历,最后一个相同的节点即为公共祖先

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值