这个也算是很经典的题目了,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)ui
O(n)算法: Manacher
奇数偶数统一处理,每一个字符先后一个字符串中没出现的字符
例如aba,变为了#a#b#a#,这样作的好处奇数、偶数统一处理。
定义数组p[i],表示以i为中心[i – x ... i + x]是最长且回文的。
仍是上例:
#a#b#a#
0103010
P[i]其实表示了原串中以该字符为中心的最长回文子串的长度(#表示原串中两个字符之间的位置为中心)。
咱们可否O(n)时间求出p数组?spa
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’],由于框住的东西比较过了。.net
若是框不住p[i’]的长度,致使其超出i + p[i’]右边界,就是框不住的东西,是须要比较的。code
p[i]至少等于min{p[i’], right – i}。
继续暴力比较,更新right。
为啥算法是O(n)的?由于right只能增长n次……blog
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的和。get