二元最近的共同祖先问题(O(n) time 而且,只有一次遍历,O(1) Space (它不考虑函数调用栈空间))

二元最近的共同祖先问题(O(n) time 而且,只有一次遍历,O(1) Space (它不考虑函数调用栈空间))

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

问题:

找到两个节点的二叉树的最近的共同祖先。

首先可以参考这个博客http://blog.csdn.net/cxllyg/article/details/7635992 ,写的比較具体,包含了节点包含父指针和不包含父指针的情况,还介绍了经典的Tarjan算法。

Tarjan算法非常精妙,可是使用了并查集,须要额外O(n)的存储空间。

上面博客中给的第三个方法也是须要记录根到节点的路径,须要O(log n)空间,当然考虑到普通情况下我们遍历树都是递归的方式。所以本身方法调用栈就是O(log n)空间占用率。 可是这是对于平衡的二叉树而言的。在最差情况下空间占用率还是O(n)。

所以。这里我给的算法不须要记录根到节点的路径。并且只遍历树一遍就能够完毕。

1. 首先深度遍历树,找到第一个节点,如果为p。这时设置两个节点的近期公共祖先为p

2. 继续深度遍历,找另外一个节点q, 如果这时找到q, 那么二者近期祖先就是p.

3. 否则,回退到上一层,这时二者的近期公共祖先也对应改成了p的父节点。由于以p为根的子树中没有发现另外一个节点q

4. 依此类推。找不到则继续回退到上一层,当找到q时,相应的二者近期公共祖先也就找到了。

5. 若是p==q,直接返回p作为近期公共祖先

6. 若二者不都存在于树中,则返回空。


public class CommonAncestor {

	public static void main(String[] args) {

		CommonAncestor ca=new CommonAncestor();
		TreeNode root=new TreeNode(0);
		TreeNode l1=new TreeNode(-1);
		TreeNode r1=new TreeNode(1);
		root.left=l1;
		root.right=r1;
		
		TreeNode l1l1=new TreeNode(-2);
		TreeNode l1r1=new TreeNode(-3);
		l1.left=l1l1;
		l1.right=l1r1;
		
		TreeNode r=ca.commonAncestor(root, l1, r1);
		System.out.println(r.val);
	}
	
	private TreeNode ancestor=null;
	private TreeNode firstFound=null;
	private boolean found=false;
	public CommonAncestor()
	{
		
	}
	
	public TreeNode commonAncestor(TreeNode root,TreeNode p,TreeNode q)
	{
		this.ancestor=null;
		this.found=false;
		findCommonAncestor(root,p,q);
		if(found)
			return ancestor;
		else
			return null;
	}

	private void findCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {

		if(root==null)
			return ;
		if(found)
			return;
		this.findCommonAncestor(root.left, p, q);
		test(root,p,q);
		this.findCommonAncestor(root.right, p, q);
		test(root,p,q);
	}

	private void test(TreeNode root, TreeNode p, TreeNode q) {

		if(found)
			return;
		if(this.ancestor==null)
		{
			if(root==p)
			{
				this.ancestor=p;
				firstFound=p;
				if(p==q)
					found=true;
			}
			else if(root==q)
			{
				this.ancestor=q;
				firstFound=q;
				if(p==q)
					found=true;
			}
			
			
		}
		else
		{
			if(root.left==this.ancestor||root.right==this.ancestor)
			{
				this.ancestor=root;
			}
			if((root==p||root==q)&&root!=firstFound)
			{
				found=true;
			}
		}
	}

}


版权声明:本文博主原创文章。博客,未经同意不得转载。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/117080.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • adobe flash cookies可以清理吗(跟踪号码不让对方知道)

    如果你喜欢对自己的浏览内容保密,或许在会话结束之后,你已经清理了你的历史记录和cookies,你的痕迹并没有完全被清理干净。还有一种称为FlashCookies或LocalSharedObjects(LSOs)的cookies还没有被清理。今天,我们将看看如何摆脱这些烦人的文件,更好的保护自己的隐私。它们是什么?FlashCookies或LSOs…

    2022年4月12日
    36
  • 判断一个数是否为素数c#(判断一个数是否为素数的算法)

    C++判断一个数是否为素数算法C++判断一个数是否为素数算法完整源码(定义,实现,main函数测试)C++判断一个数是否为素数算法完整源码(定义,实现,main函数测试)#include<cassert>#include<iostream>template<typenameT>boolis_prime(Tnum){boolresult=true;if(num<=1){return0;

    2022年4月15日
    42
  • centos安装python3.7_怎么给电脑安装java环境

    centos安装python3.7_怎么给电脑安装java环境可通过以下命令来查看操作系统的具体版本,本例中采用的是CentOS7.6。一般来说,CentOS中默认已经安装有python2.x,因为有一些系统命令可能会需要用到python2,所以不能卸载。我们只需再安装python3.x即可

    2022年9月24日
    2
  • 完全二叉树与满二叉树的区别(有图)[通俗易懂]

    完全二叉树与满二叉树的区别(有图)[通俗易懂]先看图:完全二叉树:设二叉树的深度为h,除第h层外,其它各层(1~h-1)的结点数都达到最大个数,第h层所有的结点都连续集中在最左边满二叉树:深度为k且有2^k-1个结点的二叉树称为满二叉树

    2022年7月13日
    26
  • jedispool 连接池_redis-cli连接redis数据库

    jedispool 连接池_redis-cli连接redis数据库一、连接前的准备1.确保windows能够ping通linux,linux能够ping通windows。2.开放CentOS7的端口6379。firewall-cmd–add-port=6379/tcp–permanent3.注释掉redis.conf文件中的bind。#bind127.0.0.14….

    2025年9月12日
    9
  • jar包和war包区别及理解

    jar包和war包区别及理解在开发阶段不适合使用war包,因为在开发阶段,经常需要添加或删除Web应用程序的内容,更新Servlet类文件,而每一次改动后,重新建立war包将是一件浪费时间的事情。在产品发布阶段,使用war文件比较合适的,因为在这个时候,几乎不需要再做什么改动了。jar包jar是类的归档文件JAR(JavaArchive,Java归档文件)是与平台无关的文件格式,它允许将许多文件组合成一个压缩文件,为J2EE应用程序创建的jar文件是EAR文件(企业jar文件),jar文件格式以流行的ZIP文

    2022年5月24日
    35

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号