情形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;
}
}
测试:
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 path1 = new Stack();
boolean flag1 = getThePathOfTheNode(root, node1,path1);
if(!flag1){//树上没有node1节点
return null;
}
Stack path2 = new Stack();
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 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