1. 程式人生 > >51Nod1089最長回文子串 V2(Manacher算法)

51Nod1089最長回文子串 V2(Manacher算法)

維護 ora div text clas i++ 情況 超出 手動

俗稱馬拉車算法→_→

處理最長回文字串復雜度O(n)

這裏菜雞不會證,簡單說一下思路。

由於回文串有奇有偶,所以將串之間和兩邊加上‘#‘,為了防止後面某個地方超邊界,新串0位置加上$。這樣每個回文子串為#a#b#a#形式,必定奇數個,且原子串長度為新字串半徑減一,求這個半徑p[i]。(即p[i]是以i為中心的最長回文字串的半徑)

i從1到n,過程中維護一個id點(id<i,i拉著id走,馬拉車),它是某個回文子串的中心,這個字串右邊界是當前最大的。(p[i]是半徑,故i+p[i]為邊界)

那麽當右邊界比i還大時,就可以根據對稱性,找到i關於id的對稱點j=2*id-i,來優化找字串的過程。怎麽優化呢?在id管轄範圍內,p[i]和p[j]情況是相同的。由於超出id右邊界的的地方不符合對稱性,因此p[i]=p[j]當且僅當p[j]小於等於j-(id-p[id])(即j串的左邊界不超出id串的左邊界),否則只能直接到id右邊界,p[i]=mx-i,之後的手動算。

如果id右邊界太小,不能做優化,也得手動算。

以下代碼:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #define ll long long
 6 using namespace std;
 7 char s[100020],sn[200020];
 8 int p[200020];
 9 int init(){
10     int len=strlen(s);
11     sn[0]=$;sn[1
]=#; 12 int j=2; 13 for(int i=0;i<len;i++){ 14 sn[j++]=s[i]; 15 sn[j++]=#; 16 } 17 sn[j]=\0; 18 return j; 19 } 20 int Manacher(){ 21 int len=init(); 22 int mx_len=-1,id,mx=0; 23 for(int i=1;i<len;i++){ 24 if(i<mx){ 25 p[i]=min(p[2
*id-i],mx-i); 26 } 27 else{ 28 p[i]=1; 29 } 30 while(sn[i-p[i]]==sn[i+p[i]]) p[i]++; 31 if(p[i]+i>mx){ 32 id=i; 33 mx=p[i]+i; 34 } 35 mx_len=max(mx_len,p[i]-1); 36 } 37 return mx_len; 38 } 39 int main(){ 40 cin>>s; 41 cout<<Manacher(); 42 return 0; 43 }

51Nod1089最長回文子串 V2(Manacher算法)