manacher(馬拉車)算法


斷斷續續地看了兩天的馬拉車算法,可算是給搞明白了(賊開心),這算是自己搞懂的第一個算法了(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;
        }
    }
View Code

OK以上就是自己總結的馬拉車算法了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM