(回文串)Manacher算法
(回文串)Manacher算法
標(biāo)簽: ACM 回文串 Manacher
問(wèn)題描述:
輸入一個(gè)字符串,求出其中最大的回文子串。子串的含義是:在原串中連續(xù)出現(xiàn)的字符串片段。回文的含義是:正著看和倒著看相同,如abba和yyxyy。
解析:
這里介紹O(n)回文子串(Manacher)算法
算法基本要點(diǎn):首先用一個(gè)非常巧妙的方式,將所有可能的奇數(shù)/偶數(shù)長(zhǎng)度的回文子串都轉(zhuǎn)換成了奇數(shù)長(zhǎng)度:在每個(gè)字符的兩邊都插入一個(gè)特殊的符號(hào)。比如 abba 變成 #a#b#b#a#, aba變成 #a#b#a#。 為了進(jìn)一步減少編碼的復(fù)雜度,可以在字符串的開(kāi)始加入另一個(gè)特殊字符,這樣就不用特殊處理越界問(wèn)題,比如$#a#b#a#。
下面以字符串12212321為例,經(jīng)過(guò)上一步,變成了 S[] = “$#1#2#2#1#2#3#2#1#”;
然后用一個(gè)數(shù)組 P[i] 來(lái)記錄以字符S[i]為中心的最長(zhǎng)回文子串向左/右擴(kuò)張的長(zhǎng)度(包括S[i]),比如S和P的對(duì)應(yīng)關(guān)系:
S # 1 # 2 # 2 # 1 # 2 # 3 # 2 # 1 # P 1 2 1 2 5 2 1 4 1 2 1 6 1 2 1 2 1 (p.s. 可以看出,P[i]-1正好是原字符串中回文串的總長(zhǎng)度)下面計(jì)算P[i],該算法增加兩個(gè)輔助變量id和mx,其中id表示最大回文子串中心的位置,mx則為id+P[id],也就是最大回文子串的邊界。
這個(gè)算法的關(guān)鍵點(diǎn)就在這里了:如果mx > i,那么P[i] >= MIN(P[2 * id - i], mx - i)。
具體代碼如下:
if(mx > i) {p[i] = (p[2*id - i] < (mx - i) ? p[2*id - i] : (mx - i)); } else {p[i] = 1; }當(dāng) mx - i > P[j] 的時(shí)候,以S[j]為中心的回文子串包含在以S[id]為中心的回文子串中,由于 i 和 j 對(duì)稱,以S[i]為中心的回文子串必然包含在以S[id]為中心的回文子串中,所以必有 P[i] = P[j],見(jiàn)下圖。
當(dāng) P[j] > mx - i 的時(shí)候,以S[j]為中心的回文子串不完全包含于以S[id]為中心的回文子串中,但是基于對(duì)稱性可知,下圖中兩個(gè)綠框所包圍的部分是相同的,也就是說(shuō)以S[i]為中心的回文子串,其向右至少會(huì)擴(kuò)張到mx的位置,也就是說(shuō) P[i] >= mx - i。至于mx之后的部分是否對(duì)稱,就只能一個(gè)一個(gè)匹配了。
對(duì)于 mx <= i 的情況,無(wú)法對(duì) P[i]做更多的假設(shè),只能P[i] = 1,然后再去匹配了
下面給出原文,進(jìn)一步解釋算法為線性的原因
源代碼:
#include <iostream> #include <string> #include <cstring>using namespace std;void findBMstr(string& str) {int *p = new int[str.size() + 1];memset(p, 0, sizeof(p));int mx = 0, id = 0;for(int i = 1; i <= str.size(); i++){if(mx > i){p[i] = (p[2*id - i] < (mx - i) ? p[2*id - i] : (mx - i));}else{p[i] = 1;}while(str[i - p[i]] == str[i + p[i]])p[i]++;if(i + p[i] > mx){mx = i + p[i];id = i;}}int max = 0, ii;for(int i = 1; i < str.size(); i++){if(p[i] > max){ii = i;max = p[i];}}max--;int start = ii - max ;int end = ii + max;for(int i = start; i <= end; i++){if(str[i] != '#'){cout << str[i];}}cout << endl;delete p; }int main() {string str = "12212321";string str0;str0 += "$#";for(int i = 0; i < str.size(); i++){str0 += str[i];str0 += "#";}cout << str0 << endl;findBMstr(str0);return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/Archger/p/8451664.html
總結(jié)
以上是生活随笔為你收集整理的(回文串)Manacher算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 函数模板的使用说明
- 下一篇: MapReduce01