8.5 最长回文子串
定义字符串S的逆序为S’,有S’[i]=S[n - i - 1](0 ≤ i < len(S),下文所有i处于这个区间内)。其中len(S)为S的长度。如果S和S’相同,则称S为回文串(Palindrome)。S的最长回文子串就是S的所有子串中是回文串且长度最长的字符串。
定义Suffix(S, i)为S以S[i]开头且包含S[i]的后缀字符串。
定义Prefix(S, i)为S以S[i]结尾且包含S[i]的后缀字符串。
令n = Len(S)
可知有如下性质:
1. Len(S’) = Len(S) = n;
2. Len(Suffix(S, i)) = Len(S) - i;
3. Len(Prefix(S, i)) = i;
4. Prefix(S, i) = Suffix’(S’, len(S) - i- 1);
5. Suffix(S, i) = Prefix’(S’, len(S) - i- 1);
6. (S’)’ = S.
要求S的最长回文子串,可以对i在区间[0, len(S))内枚举,找出以S[i]为中心字符的最长回文子串。所有这些回文子串中最长的那个就是S的最长回文子串。
求以S[i]为中心字符的最长回文子串的问题可以描述为:
求一对下标(j, k),满足下列条件:
1. 0 ≤ j ≤ i, i ≤ k < len(S)。因为j,k是S的下标,且一个比i小,一个比i大。
2. i - j = k - i = x。因为所求字符串以S[i]为中心字符。
3. Suffix’(Prefix(S, i), j) = Prefix(Suffix(S,i), k - i) = T。因为所求字符串为回文字符串。
4. x最大
可知在满足条件1的情况下,有:
Suffix’(Prefix(S, i), j)
= Prefix’’(Prefix’(S, i), Len(Prefix(S,i)) - j - 1) 性质5
= Prefix’’(Prefix’(S, i), i + 1 - j - 1) 性质3
= Prefix(Prefix’(S, i), i - j) 性质6
= Prefix(Suffix’’(S’, Len(S) - i - 1), i- j) 性质4
= Prefix(Suffix(S’, Len(S) - i - 1), i -j) 性质6
= Prefix(Suffix(S’, Len(S’) - i - 1), i -j) 性质1
= Prefix(Suffix(S’, n - i - 1), i - j)
所以第三个条件转化为:
Prefix(Suffix(S’, n - i - 1), i - j) = Prefix(Suffix(S,i), k - i)
又由于有条件2,进一步写为:
Prefix(Suffix(S’, n - i - 1), x) =Prefix(Suffix(S, i), x) = T
观察该条件,可知T是Suffix(S, i)和Suffix(S’, n - i - 1)的公共前缀。进一步地,要满足条件4,使x最大,就是使得公共前缀T最长。该最大公共前缀就是所求的以S[i]为中心字符的最长回文子串。
而求一个串的两个后缀的最长公共前缀正是后缀数组所擅长的事情,后缀数组可以在线性的预处理时间后支持O(1)的LCP询问。
所以求以S[i]为中心字符的最长回文子串的方法即为:构建字符串W = S?S',其中?是S的字符表中不存在的字符。在W中,S[i]对应W[i],S'[n - i - 1]对应W[n + 1 + n - i - 1] = W[2n - i]。故此SA[rank(i)]和SA[rank(2n - i)]的最长公共前缀就是最长回文子串,LCP(rank(i), rank(2n- i))就是最长回文子串的长度max(x)。
8.6 实例
8.6.1 最长公共子串
PKUJudgeOnline, 3450, Corporate Identity.
PKUJudgeOnline, 3080, Blue Jeans.
8.6.2 两个串的最长公共子串
PKUJudgeOnline, 2774, Long Long Message.
本文章欢迎转载,请保留原始博客链接http://blog.csdn.net/fsdev/article