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

时间:2010-08-22 07:49:39

标签: c algorithm data-structures

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

看起来非常有趣的问题。所以必须解决问题无论如何。准备面试。

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

3 个答案:

答案 0 :(得分:4)

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时停止。

解释了一套优秀的替代方法here

答案 1 :(得分:1)

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

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

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

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

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

4)从根

中删除较长路径中的D节点

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

6)将此节点作为LCA返回

答案 2 :(得分:-1)

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

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作为树的平均深度的平方根。