馬拉車算法總結


【算法簡述】

馬拉車(Manacher)算法是在O(n)時間內解決尋找源字符串的最長回文子串S的問題的算法。

朴素算法情況下對於每一個S[i]都要左右遍歷其最大回文子串,所以時間復雜度是O(n2

 

【算法原理】

充分利用之前求得的S【j】,為求S【i】服務。

預處理:在每個字符左右兩邊插入#將字符串變成奇數串

算法核心:

p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;

其中p[i]為S[i]的回文半徑,mx為i之前某一回文串右側最遠延伸到的位置,id為該回文串的中心點位置,很顯然從mx的對稱點到mx這一段是關於id對稱的。

如何利用之前求得的s[j]來求s[i]的回文串長度呢?
分情況討論
(1) 當 i在mx左側,p[j] < mx - i,即S[j]的回文子串的左端點不會超過mx的對稱點,那么很顯然S[i]的回文子串的右端點不會超過mx,所以此時取P[i] = p[j]

 

(2)當i在mx左側, p[j] > mx - i時,即S[j]的回文子串的左端點超過mx的對稱點,那么很顯然S[i]的回文子串的右端點至少要到mx,至於mx右側的,只能一個一個匹配以確定p[i]了。

(3)當i在mx右側,即i > mx,初始化p[i] = 1.這時候很顯然,mx和id是要更新的。因為此時回文串右側延伸的位置已經超過mx了。

 

【模板】

 為了最后返回字符串的參數傳入方便,在字符串加了#的基礎上又加了$

//返回源字符串S的最長回文子串 
string Manacher(string s){
    //預處理源串 
    string t = "$#";
    for(int i=0; i<s.size(); i++){
        t+=s[i];
        t+="#";
    }
    //新建p數組,大小和t串一致,初始化為0 ,p[i]表示以t[i]為中心的回文串半徑 
    vector<int> p(t.size() , 0); 
    
    //設定重要參數 mx(某回文串延伸到的最右邊下標),id(mx所屬回文串中心下標),
    //reCenter(結果最大回文串中心下標),reLen(最大長回文長度) 
    int mx = 0, id = 0, reCenter = 0, reLen = 0;
    
    //遍歷t字符串
    for(int i=1; i<t.size(); i++){
        //核心算法 
        p[i] = mx > i ? min(mx - i , p[2*id - i]) : 1;
        
        //上面的語句只能確定i~mx的回文情況,至於mx之后的部分是否對稱,就只能老老實實去匹配了,匹配一個p[i]++ 
        while(t[i + p[i]] == t[i - p[i]]) p[i]++;
        
        //當t[i]匹配的 右邊界超過mx時mx和id就更新 
        if(i+p[i] > mx){
            mx = i+p[i];
            id = i;
        }
        //更新結果數據 
        if(p[i] > reLen){
            reLen = p[i];
            reCenter = i;    
        }
    }
    
    return s.substr((reCenter - reLen) / 2 , reLen - 1)  ;
    
}

 


免責聲明!

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



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