斷斷續續地看了兩天的馬拉車算法,可算是給搞明白了(賊開心),這算是自己搞懂的第一個算法了(23333333333333)這個算法照目前自己的理解來看,貌似就只能求個字符串中的回文串(接觸這個算法是要求最長的回文串),雖然應用的范圍有點少,但還是要學習滴,不然遇到類似的題目就gg了。
可以在線性時間內求得答案,時間復雜度為O(n)。
1、回文串的個數是可奇可偶的,碰上奇數的回文串還可以,如果是偶數的回文串沒有着腳點,那就很惱人了。所以馬拉車算法會對字符串進行預先處理,然后再求最長的回文串。首先用字符串中沒有出現過的字符來表示串中每個元素的間隔,而為了防止在訪問時出現越界情況,需要在串首和串尾再加上額外的特殊字符。
例如:原串為ababab;處理完之后就是$#a#b#a#b#a#b#$; 其實對於最后一個$,也可以不加,因為字符串的最后一個字符是‘\0’就相當於一個特殊字符了。
//設t為將要進行預處理的字符串,則處理實現如下 string t="@#"; for(int i=0;i<str.size();i++) { t=t+str[i]; t=t+"#"; }
2、接下來就是在新串中找以每一個字符為中心的回文串就可以了。manacher算法的思想就是從左到右求出以每個字符為中心的最長回文串。設能延伸到最右邊的字符串的中心位置為id,該字符串最右端的位置為mx,pal數組來儲存此處回文串的長度。因為回文串有對稱的性質,所以后邊的字符串可以通過對稱來直接求得其長度(當然前邊的還是需要乖乖的遍歷求出來的)。
3、對於遍歷到的字符(下標設為i),一共會有三種情況;
(1)i<=mx;
情況如下圖所示(第一次用畫圖的我表示已經被逼瘋了emmmmm)

該情況下就萬事大吉了,直接把2*id-i處串的長度,復制給i就OK了。
(2)i<=mx
同樣是這種情況但是出現i處的回文串超出了mx的情況如下圖
最右端超出了mx的范圍,出現什么情況就不好說了,所以只能暴力一下,然后更新mx的大小就可以了
(3)i>mx
這種情況直接暴力,求此處回文串的長度即可。附上自己寫的代碼
int mx=0,id=0,len=0; vector<int> pal(t.size(),0); for(int i=1;i<t.size();i++) { //pal數組存的其實是此處回文串的長度+1 pal[i]=mx>i ? min(pal[2*id-i],mx-i):1;//此處為最關鍵的一處 //當 mx>i 當然是要選一個小的來賦值,這樣就可以防止超出mx了 //然后再接着暴力枚舉后邊的是不是回文串,以使它的長度增加。 //當 mx<=i時,此處的長度為1,直接進入暴力枚舉它的長度 while(t[i+pal[i]]==t[i-pal[i]] && ss.count(t[i+pal[i]])) { ++pal[i]; } //最右端回文串的長度超出mx后就要進行mx和id的更新了 if(mx < i+pal[i]) { mx = i+pal[i]; id=i; } if(len < pal[i]-1) { len=pal[i]-1; } }
OK以上就是自己總結的馬拉車算法了。

