LCA(Least Common Ancestors)问题描述:找出给定二叉树中的两个指定节点的最近公共祖先。
本文给出两种方法,一种是网上看到的,代码很简洁,另外一种是我自己优化过的,思路上更简单易懂。
第一种:
Node *LCA(Node *root, Node *p, Node *q) {
if (!root) return NULL;
if (root == p || root == q) return root;
Node *L = LCA(root->left, p, q);
Node *R = LCA(root->right, p, q);
if (L && R) return root; // 如果p和q位于不同的子树
return L ? L : R; //p和q在相同的子树,或者p和q不在子树中
}
代码非常简洁,基本思路就是在当前node的left和right中寻找目标node,如果找到就返回,没找到就返回null。
如果目标node分布在left和right,由于这个迭代算法是自底向上的,所以当前node就是最近公共祖先,否则的话必然L,R中有一个为null,另外一个不是null,此时返回非null的即可,说得比较绕,慢慢回想就能理解。
第二种,自己的方法:
private static int targetX=0;
private static int targetY=0;
private static Hashtable<Integer,Node> r= new Hashtable<Integer,Node>();
public static Node findLCA(Node root,String x,String y,int index){
if(root != null){
if(root.data.equals(x)){
targetX = index;
}
if(root.data.equals(y)){
targetY = index;
}
r.put(index, root);
findLCA(root.left,x,y,index*2);
findLCA(root.right,x,y,index*2+1);
}
if(index == 1){
while(targetX!=targetY){
if(targetX>targetY){
targetX /= 2;
}
else{
targetY /=2;
}
}
return r.get(targetX);
}
else{
return null;
}
}
主要思路就是给每一个结点赋一个下标,对于下标为index的node的left和right,下标分别为index*2,index*2+1。这样就可以给每一个结点一个下标,也只需要遍历一遍树即可完成任务。举例说明:对于结构如下的二叉树
我的算法默认根节点下标为1,通过我的算法得到a,b,c,d,e,f的下标为:1,2,3,6,7,12
而知道了下标计算 公共祖先就非常简单,将两个目标节点的下标中大的那个不断除以2,直到相等为止。思路非常明确,通过下标的倍数关系将结点的父子关系反应出来。简单易懂。例如要求b和d的LCA,就取出下标2和6,d的父结点c的下标为:6/2=3,3依然大于b的下标2,所以继续找c的父节点的下标:3/2=1,此时2/2=1,所以他们的LCA就是下标为1的结点a!
除以2的过程相当于将当前节点到根节点所经过的结点全部找到了,如果将两个目标结点的这个结点序列标记为L1和L2,那么我的代码的后半部分就是在找L1和L2的第一个交叉结点。