1. 程式人生 > >【文文殿下】Manache算法-學習筆記

【文文殿下】Manache算法-學習筆記

inf 最長回文子串 學習筆記 解釋 ont 最長 reg 開頭 時間復雜度

Manache算法

  是一個判斷回文子串的算法,我們結合例題解釋:

  

     題目:給定一個長度為 n 的字符串 S,求其最長回文子串 一個字符串是回文的,當且僅當反轉後的串與原串完全相等

   對於這個題目,有三種主流思路:

      一:Hash+二分

            計算字符串的前綴hash值

            枚舉中點,二分回文字串的長度

            時間復雜度:$O(nlogn)$

        二:回文自動機

         復雜度是線性的,但是編程復雜度極高,思維難度極高。

       三:Manache算法

      復雜度是線性的,思維難度低,編程難度低


      對於Manache算法,我們先考慮樸素做法:枚舉回文串中心,然後向兩邊擴展,這樣的復雜度是$O(N^2)$的,

      但是類比KMP算法,我們在樸素算法中,沒有考慮到已經計算的部分對於之後結果的貢獻,樸素方法的突破口就在這裏了。

      考慮優化:由於回文串長度分奇偶,有點麻煩,所以,我們考慮在每個字符中間插入一個‘#‘字符,來保證字符串的奇性。特別的,在字符串前兩個字符,插入\$和#,對於\$的作用是:防止數組越界,既下文代碼中的whie()函數,來確保其遇到字符串開頭立即停止(因為對於$字符,其為唯一的,不可能有字符與其匹配)。

      我們引入輔助數組$len[i]$ 來表示以$i$為中心,最大回文串的半徑,顯然的,對於每一個$len[i]$,$len[i]-1$就是原來回文串的長度,我們結合一個樣例來說明:

      原字符串:$ # A # B # A # A # B #

      $len$數組  1 1 2 1 4 1 2 2 2 1 2 1

      原來的最長回文串是$3$ 也就是$len[4]-1$ (從0開始標號)。

      對吧?

      接下來的問題,就是如何計算$len$數組了 , 這確實是個問題,不過我們可以通過下面的辦法解決:

      考慮$len[i]$ 以及當前求出的回文右邊界$mx$ , $id$ 是對應的回文中心,如果$i<mx$ 則附上初值$min{mx-i,p[j]}$,其中,$j$是$i$關於$id$的對稱坐標,通過中點坐標公式,我們可以得出:$j=id*2-i$ 。

      否則($i>=mx$)附上初值$len[i]=1$.

      然後,向兩邊擴展就好了。可以結合下面的圖像理解:

      技術分享圖片

         帶有下劃線的部分,是已經計算得出的回文串。

      代碼實現:

      

void Manache() {
    int pos=0,mx=0;
    for(register int i=1;i<=n;++i) {
        len[i]=i<mx?min(len[(pos<<1)-i],mx-i):1;
        while(b[i-len[i]]==b[i+len[i]]) len[i]++;
        if(i+len[i]>mx) mx=i+len[i],pos=i;
    }
}

【文文殿下】Manache算法-學習筆記