求最长回文子串与最长重复子串。
长沙雅礼中学
何林
【介绍】
问题的提出:
问题
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
的最长公共