【面试题】最长回文子串

这个也算是很经典的题目了,O(n)的解法还是要自己钻进去想一想的,不能总以为自己会了,动手写一写才是王道。

今天看了2013年9月15日北理工面试&算法讲座by_July&曹鹏的PPT,真是后悔当时没去听啊,已经不记得当时干什么去了,反正应该没有去听讲座有意义。。正题,然后又看到这个题,第N次看到了,却还没写过,实在不应该,今天就写了一下。话说,推荐 结构之法 算法之道 博客,博客置顶的博文里面可以找到PPT下载地址。

题大家应该都知道,我就直接用PPT里面的了。

例如ababcdedcbaab, 最长回文子串是abcdedcba。
暴力解法1:
枚举起点O(n)
枚举终点O(n)
判断回文O(n)
总复杂度O(n^3)
暴力解法2:
枚举中间点O(n) (可能是两个字符之间,可能是1个字符)
不断延伸判断回文O(n)
总复杂度O(n^2)

O(n)算法: Manacher
奇数偶数统一处理,每个字符前后一个字符串中没出现的字符
例如aba,变为了#a#b#a#,这样做的好处奇数、偶数统一处理。
定义数组p[i],表示以i为中心[i – x ... i + x]是最长且回文的。
还是上例:
#a#b#a#
0103010
P[i]其实表示了原串中以该字符为中心的最长回文子串的长度(#表示原串中两个字符之间的位置为中心)。
我们能否O(n)时间求出p数组?

Manacher算法
算p[i]时假设p[0 ... i – 1]已经计算好了,对前面的p[x],我们定义一个框[x – p[x] ... x + p[x]],定义right是max{x + p[x]}, center = argmax{x + p[x]},即right是之前所有框的最右边的位置,center是这个框的中心,框里的串是个回文子串。
现在要计算p[i],我们算一下其关于center的对称点i’ = center * 2 – i,问题关键是回文串的对称性,从框左边left...i’和i...right是一致的,如果p[i’]的长度能把i + p[i’]限制在框里,则有p[i] = p[i’],因为框住的东西比较过了。

如果框不住p[i’]的长度,导致其超出i + p[i’]右边界,就是框不住的东西,是需要比较的。

【面试题】最长回文子串_第1张图片

p[i]至少等于min{p[i’], right – i}。
继续暴力比较,更新right。
为啥算法是O(n)的?因为right只能增加n次……

code:

 1 int MaxHuiwen(string str)
 2 {
 3     if(str.empty())
 4         return 0;
 5     string strCharp = "#";
 6     for(int i = 0; i < str.length(); ++i)
 7     {
 8         strCharp += str[i];
 9         strCharp += "#";
10     }
11     int len = strCharp.length();
12     int *p = new int[len];
13     p[0] = 0;
14     int l = 0, c = 0, r = 0, maxl = 1;
15     for(int i = 1; i < len; ++i)
16     {
17         int j = (c << 1) - i;
18         if(j >= 0 && i + p[j] < r)
19             p[i] = p[j] < r - i ? p[j] : r - i;
20         else
21         {
22             for(p[i] = 0; i-p[i]-1 >= 0 && i+p[i]+1 < len && strCharp[i+p[i]+1] == strCharp[i-p[i]-1]; ++p[i]);
23             c = i;
24             r = i+p[i];
25             l = i-p[i];
26         }
27         maxl = maxl > p[i] ? maxl : p[i];
28     }
29     delete p;
30     return maxl;
31 }

扩展(codility Gammar 2011)
给定一个全部由字母组成的字符串,求这样的下标对数(x,y)满足x < y并且[x...y]的字符串是回文的。如果数量超过10^8,返回-1。
p数组告诉我们什么?
如果p[i] = 6表示,我们实际上有一个以i为中心长度为6的回文串,那么长度为4和2依然是回文的,实际上包含了3个回文串。
如果p[i] = 5,实际上我们有3个长度分别为5,3,1的回文串。
我们不要长度为1的,也就是说我们求的是所有p[i]/2的和。

你可能感兴趣的:(面试题)