這個也算是很經典的題目了,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