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

情形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

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

时间: 2024-08-10 19:54:30

求树中两个节点的最低公共祖先的相关文章

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

树是二叉查找树的情况 题目来自LeetCode:https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ Lowest Common Ancestor of a Binary Search Tree Total Accepted: 3402 Total Submissions: 8709 My Submissions Question Solution Given a binary search t

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

情况1: 树为二叉排序树. 思路:从根结点开始和输入的两个结点进行比较,如果当前结点的值比两个结点的值都大,那么最低的祖先肯定在左子树中,于是下一步遍历当前结点的左子结点.如果当前结点的值比两个结点的值都小,那么最低的祖先肯定在右子树种,于是下一步遍历当前结点的右子结点.如果当前结点正好是输入的两个结点之一,说明这两个结点有一个是另一个的祖先,这时输出当前结点的父节点即可. /* 二叉树的公共祖先系列 1.二叉树为二叉排序树 by Rowandjj 2014/8/20 */ #include<i

C++算法之 求二叉树两个节点的最低公共节点

方法1:递归方法: (1)如果两个节点分别在根节点的左子树和右子树,则返回根节点 (2)如果两个节点都在左子树,则递归处理左子树:如果两个节点都在右子树,则递归处理右子树 bool FindNode(BTree* pRoot, BTree* pNode) { if (pRoot == NULL || pNode == NULL) { return false; } if (pRoot == pNode) { return true; } bool found = FindNode(pRoot->

寻找二叉树两个节点的最低公共祖先

从root开始遍历,如果n1和n2中的任一个和root匹配,那么root就是LCA. 如果都不匹配,则分别递归左.右子树,如果有一个 key(n1或n2)出现在左子树,并且另一个key(n1或n2)出现在右子树,则root就是LCA.  如果两个key都出现在左子树,则说明LCA在左子树中,否则在右子树. /* 只用一次遍历解决LCA */ #include <iostream> using namespace std; struct Node { struct Node *left, *ri

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

tag: 二叉树 思路一: 分治 思路二:非递归??? package com.zhaochao.tree; /** * Created by zhaochao on 17/1/24. * lowest common ancestor */ public class LCA { // 在root为根的二叉树中找A,B的LCA: // 如果找到了就返回这个LCA // 如果只碰到A,就返回A // 如果只碰到B,就返回B // 如果都没有,就返回null public TreeNode LCARe

Lowest Common Ancestor of a Binary Search Tree(树中两个结点的最低公共祖先)

题目描述: Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST. According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T tha

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

Lowest Common Ancestor of a Binary Tree Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According to the definition of LCA on Wikipedia: "The lowest common ancestor is defined between two nodes v and w as th

剑指offer-树中两个节点的最低公共祖先

普通二叉树 /** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q)

求一棵普通树的两个结点的最低公共祖先

一棵普通树,树中的结点没有指向父节点的指针,求一棵普通树的两个结点的最低公共祖先. 代码如下,我太懒没有加注释,大家自己看吧! 1 #include <iostream> 2 #include <list> 3 #include <vector> 4 using namespace std; 5 6 struct TreeNode //节点 7 { 8 char m_nValue; 9 vector<TreeNode*> m_vChildren; 10 };