二叉树的最低共同祖先(非二叉搜索树)

我尝试使用Tarjan的算法和网站上的一种算法来解决这个问题: http : //discuss.techinterview.org/default.asp?interview.11.532716.6 ,但没有一个是清楚的。 也许我的递归概念没有正确构建。 请举一个小型演示来解释上面两个例子。 我对Union Find数据结构有所了解。

这看起来很有意思。 所以必须解决问题无论如何。 准备面试。

如果存在任何其他逻辑/算法,请分享。

LCA算法尝试做一件简单的事情:找出从两个节点到根节点的路径。 现在,这两个路径将具有共同的后缀(假设路径在根处结束)。 LCA是后缀开始的第一个节点。

考虑以下树:

r * / \ s * * / \ u * * t / / \ * v * * / \ * * 

为了找到LCA(u,v),我们按如下方式进行:

  • 从u到root的路径:Path(u,r)= usr
  • 从v到root的路径:Path(v,r)= vtsr

现在,我们检查公共后缀:

  • 常见后缀:’sr’
  • 因此,LCA(u,v)=后缀的第一个节点= s

请注意,实际的算法不会一直到根。 他们使用Disjoint-Set数据结构在到达s时停止。

这里解释了一套优秀的替代方法。

既然你提到了求职面试,我想到了这个问题的变化,你只限于O(1)内存使用。

在这种情况下,请考虑以下算法:

1)从节点u扫描树到根,找到路径长度L(u)

2)从节点v扫描树到根,找到路径长度L(v)

3)计算路径长度差D = | L(u)-L(v)|

4)从根目录中删除较长路径中的D节点

5)从两个节点并行地向上走树,直到你到达同一个节点

6)将该节点作为LCA返回

假设您只需要解决一次问题(每个数据集),那么一个简单的方法是从一个节点(连同自身)收集祖先集,然后从另一个节点中走出祖先列表,直到找到一个成员为止。上面的集合,必然是最低的共同祖先。 给出了伪代码:

 Let A and B begin as the nodes in question. seen := set containing the root node while A is not root: add A to seen A := A's parent while B is not in seen: B := B's parent B is now the lowest common ancestor. 

另一种方法是计算每个节点的整个路径到房间,然后从右侧扫描以查找公共后缀。 它的第一个要素是LCA。 其中哪一项更快取决于您的数据。

如果您需要找到多对节点的LCA,那么您可以进行各种空间/时间权衡:

例如,您可以预先计算每个节点的深度,这样您就可以避免每次重新创建集合(或路径),首先从较深的节点步行到较浅节点的深度,然后再行走在锁定步骤中朝向根的两个节点:当这些路径相遇时,您具有LCA。

另一种方法是使用深度模型H的下一个祖先来注释节点,这样您首先要解决类似但小时H的问题,然后解决第一个问题的H大小的实例。 这在非常深的树上是好的,并且通常选择H作为树的平均深度的平方根。