LCA(最近公共祖先)问题的新老解法对比

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的第一个交叉结点。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值