- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
求最长回文子串与最长重复子串。
长沙雅礼中学 何林
【介绍】
问题的提出:
问题1 最长回文子串
顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为n的串S,求它最长回文子串。
问题2 最长重复子串
如果一个串x在S中出现,并且xx也在S中出现,那么x就叫做S的重复子串。
输入长度为n的串S,
本文主要涉及“最长回文子串”和“最长重复子串”这两个经典的信息学问题。把他们放在一起讨论,是因为两者的解法具有惊人的类似性。
从算法的最优性上说,两者都存在线性时间复杂度的算法——使用后缀树。无庸置疑,后缀树已经成了优化字符串处理类问题的不二法门。但是它有两个致命缺点。
后缀树的时空复杂度和字符串涉及的字符集有直接关系。称后缀树是“线性数据结构”也是建立在字符集规模为常数的假设上。因此,所谓“线性算法”,准确的说,只是“伪线性”。
实践后缀树的编程复杂度极高。如果说上一点是后缀树在理论上的硬伤,那么这一点就是后缀树在实践上的致命弱点。对时间要求很高的信息学竞赛,是不允许选手花数个小时去编写一个长而容易出错的程序的。最重要的一点是,因为字符集比较大,后缀树的实际运行效果往往不佳,甚至很容易发生空间上的爆炸。
以上两个原因限制了后缀树在竞赛中的应用,虽然它在理论上的价值是不可取代的。
一种折衷的数据结构——后缀数组——可以很好的平衡后缀树的缺点。但是其编程复杂度也不低。要求任意两个串的最长公共前缀,或者用RMQ算法、或者用线段树,这两只“老虎”都不是好惹的——几百行的程序一稍不留神就可能满盘皆错。
本文重点介绍的是一个有别于“后缀”系列的全新的算法:分治+扩展的KMP算法。它时空复杂度低,编程十分简单,而且算法原理非常好理解。更重要的是其解题思想有很深的可挖掘性。
【扩展的KMP算法】
问题的提出:
扩展的KMP问题
给定母串S,和子串T。定义n=|S|, m=|T|,extend[i]=S[i..n]与T的最长公共前缀长度。
请在线性的时间复杂度内,求出所有的extend[1..n]。
容易发现,如果有某个位置i满足extend[i]=m,那么T就肯定在S中出现过,并且进一步知道出现首位置是i——而这正是经典的KMP问题。
因此可见“扩展的KMP问题”是对经典KMP问题的一个扩充和加难。
来看一个例子S=’aaaaaaaaaabaaa’, T=’aaaaaaaaaaa’。
extend[1]=10
这里为了计算extend[1],我们进行了11次比较运算。
然后我们要算extend[2]:
extend[2]=9。为了计算extend[2],我们是不是也要进行10次比较运算呢?不然。
因为通过计算extend[1]=10,我们可以得到这样的信息:S[1..10]=T[1..10](S[2..10]=T[2..10]。
计算extend[2]的时候,实际上是S[2]开始匹配T。因为S[2..10]=T[2..10],所以在匹配的开头阶段是“以T[2..10]为母串,T为子串”的匹配。
不妨设辅助函数next[i]表示T[i..m]与T的最长公共前缀长度。
对于这个例子,next[2]=10。也就是说:
T[2..11]=T[1..10](T[2..10]=T[1..9](S[2..10]=T[1..9]。
这就是说前9位的比较是完全可以避免的!我们直接从S[11](T[10]开始比较。这时候一比较就发现失配,因此extend[2]=9。
以上的例子是有代表性。下面提出一般的算法。
设extend[1..k]已经算好,并且在以前的匹配过程中到达的最远位置是p。最远位置严格的说就是i+extend[i]-1的最大值,其中i=1,2,3,…,k;不妨设这个取最大值的i是a。(下图黄色表示已经求出来了extend的位置)
根据定义S[a..p]=T[1..p-a+1](S[k+1..p]=T[k-a+2..p-a+1],令L=next[k-a+2]。有两种情况。
第一种情况k+Lp,如下图:
上面的红色部分是相等的。蓝色部分肯定不相等,否则就违反了“next[i]表示T[i..m]与T的最长公共前缀长度”的定义。(因为next[k-a+2]=L,如果蓝色部分相等的话,那么就有next[k-a+2]=L+1或者更大,矛盾)。
这时候我们无需任何比较就可以知道extend[k+1]=L。同时a, p的值都保持不变,k(k+1,继续上述过程。
第二种情况k+L=p。如下图:
上图的紫色部分是未知的。因为在计算extend[1..k]的时候,到达过的最远地方是p,所以p以后的位置从未被探访过,我们也就无从紫色部分是否相等。
这种情况下,就要从S[p+1](T[p-
文档评论(0)