最近公共祖先LCA的几种解决方案

来源:互联网 发布:阿里云 不同可用区互通 编辑:程序博客网 时间:2024/06/06 00:54

问题是,已经知道一棵二叉树的根结点root和其中的两个结点p1和p2,求p1与p2的最近公共祖先

 

有几种不同的方法:

 

方法一,
给每个结点记数,除了p1和p2指向的结点记为1外,其余结点的均记为0

然后采用后序遍历的方法,依次计算每个结点其左结点和右结点的和,第一个发现的和为2的结点,即所求结点,如果和不为2,则更新当前结点的值,直到找到一个结点和为2为止。

 

方法二,
我们来看这样一棵二叉树

        (1)
       /    /
     (2)   (7)
     /   /      /
   (3)   (4)   (8)
          /   /
        (5)   (6)

我们按照某种规律来遍历整棵树,得到结点访问顺序为

1 2 3 2 4 5 4 6 4 2 1 7 8 7 1

其对应的结点深度为

0 1 2 1 2 3 2 3 2 1 0 1 2 1 0

 

比如我们来查询结点3和结点6的最近公共祖先,考虑在访问顺序中结点3和结点6第一次出现之间的序列

3 2 4 5 4 6,这是由结点3到结点6之间的一条路径

在这条路径中,深度最小的结点就是所求的最近公共祖先,即结点2

 

于是问题转化为,给定一个数组,及两个位置i和j,如何找出数组R中从位置i到位置j的最小值

这个问题就是典型的RMQ问题

 

RMQ问题有一个简单的方法来解决,但需要先进行一下预处理

用一个数组d[i][j]表示数组R中,[ i, i + 2 ^ j - 1 ]这段区间中的最小值

这个d[i][j]很容易得到,因为有方程

d[ i ][ j + 1 ] = min { d[i][ j ], d[ i + 2 ^ j ][ j ] }

预处理的空间复杂度是O(nlogn),时间复杂度也是O(nlogn)

 

如果询问从a到b里的最小值,思路是找两个长度为2^k的区间,即

[ a, a + 2 ^ k - 1 ]及[ b - 1 - 2 ^ k, b ]把区间[a, b]覆盖掉

只要 2 ^ ( k + 1 ) >= | b - a |
就能找到这个k 

 

所以区间[a,b]中的最小值是 min{ d[ a ][ k ], d[ b - 2 ^ k - 1 ][ k ] }

 

原创粉丝点击