求树中两个节点的最低公共祖先

情形1:树是搜索二叉树

思路:从树的根节点开始遍历,如果根节点的值大于其中一个节点,小于另外一个节点,则根节点就是最低公共祖先。否则如果根节点的值小于两个节点的值,则递归求根节点的右子树,如果大于两个节点的值则递归求根的左子树。如果根节点正好是其中的一个节点,那么说明这两个节点在一条路径上,所以最低公共祖先则是根节点的父节点

public static BinaryTreeNode getLowestCommonAncestor(BinaryTreeNode rootParent,BinaryTreeNode root,BinaryTreeNode node1,BinaryTreeNode node2){
		if(root == null || node1 == null || node2 == null){
			return null;
		}
		if((root.value - node1.value)*(root.value - node2.value) < 0){
			return root;
		}else if((root.value - node1.value)*(root.value - node2.value) > 0){
			BinaryTreeNode newRoot = ((root.value > node1.value) && (root.value > node2.value)) ? root.leftNode : root.rightNode;
			return getLowestCommonAncestor(root,newRoot, node1, node2);
		}else{
			return rootParent;
		}
	}

复杂度:由于递归调用二叉树,所以时间复杂度是O(logn),空间复杂度是O(1)

测试:


public class BinaryTreeNode {
	public int value;
	public BinaryTreeNode leftNode;
	public BinaryTreeNode rightNode;
	
	public BinaryTreeNode(int value){
		this.value = value;
		leftNode = null;
		rightNode = null;
	}
}

public static void main(String[] args){
		BinaryTreeNode A = new BinaryTreeNode(4);
		BinaryTreeNode B = new BinaryTreeNode(2);
		BinaryTreeNode C = new BinaryTreeNode(6);
		BinaryTreeNode D = new BinaryTreeNode(1);
		BinaryTreeNode E = new BinaryTreeNode(3);
		BinaryTreeNode F = new BinaryTreeNode(5);
		BinaryTreeNode G = new BinaryTreeNode(7);
		A.leftNode = B;
		A.rightNode = C;
		B.leftNode = D;
		B.rightNode = E;
		C.leftNode = F;
		C.rightNode = G;
		BinaryTreeNode res1 = getLowestCommonAncestor(null, A, E, F);
		BinaryTreeNode res2 = getLowestCommonAncestor(null, A, D, E);
		BinaryTreeNode res3 = getLowestCommonAncestor(null, A, B, D);
		System.out.println("The lowest common ancestor of 3 and 5 is " +res1.value);
		System.out.println("The lowest common ancestor of 1 and 3 is " +res2.value);
		System.out.println("The lowest common ancestor of 1 and 2 is " +res3.value);
}

结果:

The lowest common ancestor of 3 and5 is 4

The lowest common ancestor of 1 and3 is 2

Thelowest common ancestor of 1 and 2 is 4


情形2:树是普通的二叉树,且树中节点有指向父节点指针

 思路:两个节点如果在两条路径上,那么类似于“求两个链表的第一个公共节点”的算法题

//含有指向父节点指针的树节点
public class NewBinaryTreeNode {
	public int value;
	public NewBinaryTreeNode parentNode;
	public NewBinaryTreeNode leftNode;
	public NewBinaryTreeNode rightNode;
	
	public NewBinaryTreeNode(int value){
		this.value = value;
		parentNode = null;
		leftNode = null;
		rightNode = null;
	}
}

public static NewBinaryTreeNode  getLowestCommonAncestor1(NewBinaryTreeNode root,NewBinaryTreeNode node1,NewBinaryTreeNode node2){
		if(root == null || node1 == null || node2 == null){
			return null;
		}
		int depth1 = findTheDepthOfTheNode(root, node1, node2);
		if(depth1 == -1){
			return node2.parentNode;
		}
		int depth2 = findTheDepthOfTheNode(root, node2, node1);
		if(depth2 == -1){
			return node1.parentNode;
		}
		//p指向较深的节点q指向较浅的节点
		NewBinaryTreeNode p = depth1 > depth2 ? node1 : node2;
		NewBinaryTreeNode q = depth1 > depth2 ? node2 : node1;
		int depth =  Math.abs(depth1 - depth2);
		while(depth > 0){
			p = p.parentNode;
			depth --;
		}
		while(p != q){
			p = p.parentNode;
			q = q.parentNode;
		}
		return p;
	}
	
	//求node1的深度,如果node1和node2在一条路径上,则返回-1,否则返回node1的深度
	public static int findTheDepthOfTheNode(NewBinaryTreeNode root,NewBinaryTreeNode node1,NewBinaryTreeNode node2){
		int depth = 0;
		while(node1.parentNode != null){
			node1 = node1.parentNode;
			depth ++;
			if(node1 == node2){
				return -1;
			}
		}
		return depth;
	}

复杂度:由于每个节点的深度最多为logn,所以时间复杂度为O(logn),空间复杂度O(1)

测试:


public static void main(String[] args){
		NewBinaryTreeNode A = new NewBinaryTreeNode(1);
		NewBinaryTreeNode B = new NewBinaryTreeNode(2);
		NewBinaryTreeNode C = new NewBinaryTreeNode(3);
		NewBinaryTreeNode D = new NewBinaryTreeNode(4);
		NewBinaryTreeNode E = new NewBinaryTreeNode(5);
		NewBinaryTreeNode F = new NewBinaryTreeNode(6);
		NewBinaryTreeNode G = new NewBinaryTreeNode(7);
		A.leftNode = B;
		A.rightNode = C;
		B.leftNode = D;
		B.rightNode = E;
		B.parentNode = A;
		C.leftNode = F;
		C.rightNode = G;
		C.parentNode = A;
		D.parentNode = B;
		E.parentNode = B;
		F.parentNode = C;
		G.parentNode = C;
		NewBinaryTreeNode res1 = getLowestCommonAncestor1(A,E,F);
		NewBinaryTreeNode res2 = getLowestCommonAncestor1(A,D,E);
		NewBinaryTreeNode res3 = getLowestCommonAncestor1(A,B,D);
		System.out.println("The lowest common ancestor of 5 and 6 is " +res1.value);
		System.out.println("The lowest common ancestor of 4 and 5 is " +res2.value);
		System.out.println("The lowest common ancestor of 2 and 4 is " +res3.value);
	}
结果:

The lowest common ancestor of 5 and6 is 1

The lowest common ancestor of 4 and5 is 2

The lowest common ancestor of 2 and4 is 1

情形3:树是普通的二叉树, 节点没有指向父节点的指针

思路:用栈来实现类似于指向父节点指针的功能

public static BinaryTreeNode getLowestCommonAncestor2(BinaryTreeNode root, BinaryTreeNode node1, BinaryTreeNode node2){
		if(root == null || node1 == null || node2 == null){
			return null;
		}
		Stack<BinaryTreeNode> path1 = new Stack<BinaryTreeNode>();
		boolean flag1 = getThePathOfTheNode(root, node1,path1);
		if(!flag1){//树上没有node1节点
			return null;
		}
		Stack<BinaryTreeNode> path2 = new Stack<BinaryTreeNode>();
		boolean flag2 = getThePathOfTheNode(root, node2,path2);
		if(!flag2){//树上没有node2节点
			return null;
		}
		if(path1.size() > path2.size()){ //让两个路径等长
			while(path1.size() !=  path2.size()){
				path1.pop();
			}
		}else{
			while(path1.size() !=  path2.size()){
				path2.pop();
			}
		}
		if(path1.equals(path2)){//当两个节点在一条路径上时
			path1.pop();
			return path1.pop();
		}else{
			BinaryTreeNode p = path1.pop();
			BinaryTreeNode q = path2.pop();
			while(q != p){
				p = path1.pop();
				q = path2.pop();
			}
			return p;
		}
	} 
	
	//获得根节点到node节点的路径
	public static boolean getThePathOfTheNode(BinaryTreeNode root,BinaryTreeNode node,Stack<BinaryTreeNode> path){
		path.push(root);
		if(root == node){
			return true;
		}
		boolean found = false;
		if(root.leftNode != null){
			found = getThePathOfTheNode(root.leftNode, node, path);
		}
		if(!found && root.rightNode != null){
			found = getThePathOfTheNode(root.rightNode, node, path);
		}
		if(!found){
			path.pop();
		}
		return found;
	}
复杂度:获取node节点的路径时间复杂度为O(n),所以总的时间复制度是O(n),空间复杂度是O(logn)

测试:


public static void main(String[] args){
		BinaryTreeNode A = new BinaryTreeNode(1);
		BinaryTreeNode B = new BinaryTreeNode(2);
		BinaryTreeNode C = new BinaryTreeNode(3);
		BinaryTreeNode D = new BinaryTreeNode(4);
		BinaryTreeNode E = new BinaryTreeNode(5);
		BinaryTreeNode F = new BinaryTreeNode(6);
		BinaryTreeNode G = new BinaryTreeNode(7);
		A.leftNode = B;
		A.rightNode = C;
		B.leftNode = D;
		B.rightNode = E;
		C.leftNode = F;
		C.rightNode = G;
		BinaryTreeNode res1 = getLowestCommonAncestor2( A, E, F);
		BinaryTreeNode res2 = getLowestCommonAncestor2( A, D, E);
		BinaryTreeNode res3 = getLowestCommonAncestor2( A, B, D);
		System.out.println("The lowest common ancestor of 5 and 6 is " +res1.value);
		System.out.println("The lowest common ancestor of 4 and 5 is " +res2.value);
		System.out.println("The lowest common ancestor of 2 and 4 is " +res3.value);
	}
结果:

The lowest common ancestor of 5 and6 is 1

The lowest common ancestor of 4 and5 is 2

The lowest common ancestor of 2 and 4 is 1


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值