没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
翻译
【原文见http://www.topcoder.com/tc?
module=Static&d1=tutorials&d2=lowestCommonAncestor】
作者:
翻译:农夫
三拳
Introduction
Notations
Range Minimum Query (RMQ)
Trivial algorithms for RMQ
A <O(N), O(sqrt(N))> solution
Sparse Table (ST) algorithm
Segment Trees
Lowest Common Ancestor (LCA)
A <O(N), O(sqrt(N))> solution
Another easy solution in <O(N logN, O(logN)>
Reduction from LCA to RMQ
From RMQ to LCA
An <O(N), O(1)> algorithm for the restricted RMQ
Conclusion
在一棵树中查找一对结点的最近公共祖先(LCA)的问题在 20 世纪末期已经被仔细的研究过了,并且
它现在已经成为算法中图论的基本算法了。这个问题之所以有趣并不是因为处理它的算法很有技巧,而是
因为它在字符串处理和生物学计算中的广泛应用,例如,当 LCA 和后缀树或者其他树形结构在一起使用
时。Harel and Tarjan
是首先深入研究这个问题的人,他们得出:在对输入树 LCA 进行线性处理后,查
询可以在常数时间内得到答案。他们的工作已经得到了广泛的延伸,这篇教程将展示一些有趣的方法,而
它们还也可以用在其他的问题上。
让我们考虑一个不太抽象的 LCA 的例子:生命树。地球上当前的居住者是由其他物种进化而来已经
是一个不争的事实。这种进化结构可以表示成一棵树,其中节点表示物种,而它的孩子结点表示从该物种
直接进化得到的物种。现在通过在树中查找一些结点的 LCA 把具有相似特征的物种划分成组,我们可以
找出两个物种共同的祖先,并且我们可以知道它们所拥有的相似特征是来自于那个祖先。
Range Minimum Query(RMQ)被用在数组中用来查找两个指定索引中具有最小值的元素的位置。
我们后面将会看到 LCA 问题可以归约成一个带限制的 RMQ 问题,其中相邻的数组元素相差 1。
尽管如此, RMQ 并不是仅仅和 LCA 一起用的。当他们在和后缀数组(一个新的数据结构,它支持和
后缀树同等效率的字符串查询,但是使用更少的内存且编码很简单)一起使用时,在字符串处理中扮演着
相当重要的角色。
在这篇教程中,我们将首先讨论 RMQ。我们将给出解决这个问题的多种方法--有一些速度比较慢但
是容易编码,而其他的则更快。在第二部分我们将讨论 LCA 和 RMQ 之间的关系。首先我们先回顾一下不
使用 RMQ 来解决 LCA 的两个简单方法;然后我们将指出 RMQ 和 LCA 问题其实是等价的;并且,最后,
我们将看到 RMQ 问题怎样规约成它的限制版本,并且对于这个特殊情况给出一个最快的算法。
!
假设一个算法预处理时间为"#$,查询时间为 #$。这个算法复杂度的标记为%"#$&#$'。我
们将用
#&($来表示数组中索引 i 和 j 之间最小值的位置。 和 ) 的离树 T 根结点最远的公共祖先
用
#&)$表示。
#$
给定数组 *&!+,找出给定的两个索引间的最小值的位置。
)-"
对每一对索引#&($,将
#&($存储在 *&!+,*&!+,表中。普通的计算将得到一个
%.#!
/
$&.#,$' 复杂度的算法。尽管如此,通过使用一个简单的动态规划方法,我们可以将复杂度降
低到%.#!
0
$&.#,$'。预处理的函数和下面差不多:
),#1!1!&1!&!$
2
&(3
"#4*3%!355$
43
"#4*3%!355$
"#(45,3(%!3(55$
"#(+,%($
(4(+,3
(4(3
6
这个普通的算法相当的慢并且使用.#!
0
$的空间,对于大数据它是无法工作的。
%.#!$&.#7#!$$'
一个比较有趣的点子是把向量分割成 7#!$大小的段。我们将在
*&7#!$+,为每一个段保存最小值的位置。
可以很容易的在 .#!$时间内预处理。下面是一个例子:
现在让我们看看怎样计算
#&($。想法是遍历所有在区间中的 7#!$段的最小值,并且和区
间相交的前半和后半部分。为了计算上图中的
#0&8$,我们应该比较 0, ,, 9 和
8,并且获得最小值的位置。可以很容易的看出这个算法每一次查询不会超过 /:7#!$次操作。
这个方法最大的有点是能够快速的编码(对于 TopCoder 类型的比赛),并且你可以把它改成问题的
动态版本(你可以在查询中间改变元素)。
;#;$-
一个更好的方法预处理 是对 0
<
的长度的子数组进行动态规划。我们将使用数组 *&!+,
*&!进行保存,其中 (是以 开始,长度为0
(
的子数组的最小值的索引。下面是一个例子
为了计算 (我们必须找到前半段区间和后半段区间的最小值。很明显小的片段有这 0
(+,
长度,因
此递归如下:
预处理的函数如下:
voidprocess2(intM[MAXN][LOGMAXN],intA[MAXN],intN)
{
inti,j;
//initializeMfortheintervalswithlength1
for(i=0;i<N;i++)
M[i][0]=i;
//computevaluesfromsmallertobiggerintervals
for(j=1;1<<j<=N;j++)
for(i=0;i+(1<<j)-1<N;i++)
if(A[M[i][j-1]]<A[M[i+(1<<(j-1))][j-1]])
M[i][j]=M[i][j-1];
else
M[i][j]=M[i+(1<<(j-1))][j-1];
}
一旦我们预处理了这些值,让我们看看怎样使用它们去计算
#&($。思路是选择两个能够完全覆盖
区间==(的块并且找到它们之间的最小值。设 <4#(+5,$.。为了计算
#&($ 我们可以
使用下面的公式
So, the overall complexity of the algorithm is %.#!!$&.#,$'。
;
为了解决 RMQ 问题我们也可以使用线段树。线段树是一个类似堆的数据结构,可以在基于区间数组
上用对数时间进行更新和查询操作。我们用下面递归方式来定义线段树的&(区间:
第一个结点将保存区间&(区间的信息
如果 i<j 左右的孩子结点将保存区间($>0和#5($>05,&(的信息
注意具有 ! 个区间元素的线段树的高度为!5,。下面是区间[0,9]的线段树:
剩余16页未读,继续阅读
资源评论
- zhui_xun_2012-12-19学术价值很高的样子,=,=
caianye
- 粉丝: 82
- 资源: 45
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- TG-2024-04-26-183849310.mp4
- 汇编语言的概要介绍与分析
- 个人博客系统设计与开发.zip
- 2023-04-06-项目笔记 - 第一百十五阶段 - 4.4.2.113全局变量的作用域-113 -2024.04.26
- 2023-04-06-项目笔记 - 第一百十五阶段 - 4.4.2.113全局变量的作用域-113 -2024.04.26
- htmlzwbjq_downyi.com.zip
- 无头单向非循环链表的实现(Test.c)
- 无头单向非循环链表的实现(SList.c)
- 浏览器重定向插件更新文件
- SSA-BP麻雀算法优化BP神经网络多特征分类预测(Matlab实现完整源码和数据)
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功