什麼是馬拉車演算法(Manacher's Algorithm)?

來源:互聯網
上載者:User

標籤:長度   sub   log   方法   csdn   左右   之間   markdown   return   

提出問題

最長迴文子串問題:給定一個字串,求它的最長迴文子串長度。

如果一個字串正著讀和反著讀是一樣的,那它就是迴文串。如a、aa、aba、abba等。

暴力解法

簡單粗暴:找到字串的所有子串,遍曆每一個子串以驗證它們是否為迴文串。一個子串由子串的起點和終點確定,對於一個長度為n的字串,共有n^2個子串。這些子串的平均長度大約是n/2,因此這個解法的時間複雜度是 \(O(n^3)\)。明顯不可取。

方法改進

迴文子串是連續的,而且是對稱的。長度為奇數迴文串以最中間字元的位置為對稱軸左右對稱,而長度為偶數的迴文串的對稱軸在中間兩個字元之間的空隙。可否利用這種對稱性來提高演算法效率呢?答案是肯定的。我們知道整個字串中的所有字元,以及字元間的空隙,都可能是某個迴文子串的對稱軸位置。可以遍曆這些位置,在每個位置上同時向左和向右擴充,直到左右兩邊的字元不同,或者達到邊界。對於一個長度為n的字串,這樣的位置一共有 n+n-1=2n-1 個,在每個位置上平均大約要進行 n/4 次字元比較,於是此演算法的時間複雜度是 \(O(n^2)\)。

另外一種改進方法是利用動態規劃,DP[i][j]定義成子串[i, j]是否是迴文串。外迴圈 i從 n?1 往 0 遍曆,內迴圈 j 從 i 往 n?1 遍曆,若s[i]==s[j]:

  • 若i==j,則dp[i][j]=true;
  • 若i和j是相鄰的,則dp[i][j]=true;
  • 若i和j中間只有一個字元,則dp[i][j]=true;
  • 否則,檢查dp[i+1][j-1]是否為true,若為true,那麼dp[i][j]就是true。

前三條可以合并,即 j?i≤2。求得dp[i][j]真值後,也可快速解決問題。時間複雜度:\(O(n^2)\)。

Manacher‘s Algorithm

對於 \(O(n^2)\) 的複雜度,或許還不滿足,是否可以再最佳化一些呢?

先分析改進方法中的缺陷,利用迴文中心需要分奇偶兩種情況討論,兩種改進都會重複訪問子串,降低效率。

Manacher‘s Algorithm正是針對這兩個問題進行進一步的改進,將時間複雜度降到了神奇的 \(O(n)\):

問題一:迴文長度奇偶性問題

為了不區分奇偶兩種情況,對字串作預先處理,在所有字元之間(包括首尾)插入相同字元如‘#‘,處理之後所有的子串都是奇數長度的。如aba→#a#b#a#。

插入的是同樣的符號,且符號不存在於原串,因此子串的迴文性不受影響,原來是迴文的串,插完之後還是迴文的,原來不是迴文的,依然不會是迴文。

問題二:重複訪問問題

定義迴文半徑:迴文串中最左或最右位置的字元與其對稱軸的距離。演算法中定義迴文半徑數組 \(RL\),\(RL[i]\) 表示以第i個字元為對稱軸的迴文串的迴文半徑。

定義 \(MaxRight\),表示當前訪問到的所有迴文子串,所能觸及的最右一個字元的位置。另外還要記錄下 \(MaxRight\) 對應的迴文串的對稱軸所在的位置,記為 \(pos\)。

核心代碼:RL[i] = i < MaxRight ? min(RL[2*pos-i], MaxRight-i) : 1;

理解了這行代碼,可以說就理解了這個演算法。我們來分情況討論:

(1)i < MaxRight時,可以再分兩種情況:

①MaxRight - i > RL[2*pos-i],如,以S[j]為中心的迴文子串包含在以S[id]為中心的迴文子串中,由於 i 和 j 對稱,以S[i]為中心的迴文子串必然包含在以S[id]為中心的迴文子串中,所以必有 P[i] = P[j]。

②MaxRight - i < RL[2*pos-i],如,以S[j]為中心的迴文子串不一定完全包含於以S[id]為中心的迴文子串中,但是基於對稱性可知,中兩個綠框所包圍的部分是相同的,也就是說以S[i]為中心的迴文子串,其向右至少會擴張到mx的位置,也就是說 P[i] >= mx - i。

(2)i > MaxRight時,無法對 P[i]做更多的假設,只能P[i] = 1,然後再去慢慢匹配了。

代碼實現

返回最長的迴文子串。代碼中resLen為處理後字串的最大迴文半徑,對應到原來的字串中時,只需-1即是整個迴文串的長度。

string Manacher(string s) {    //預先處理    string t = "#";    for (int i = 0; i < s.size(); ++i) {        t += s[i];        t += "#";    }    vector<int> RL(t.size(), 0);    int MaxRight = 0, pos = 0;    int resLen = 0, resCenter = 0;    for (int i = 0; i < t.size(); ++i) {        RL[i] = MaxRight > i ? min(RL[2 * pos - i], MaxRight - i) : 1;        while (i-RL[i] >=0 && i+RL[i] < t.size() && t[i + RL[i]] == t[i - RL[i]])//擴充,注意邊界            ++RL[i];        //更新最右端及其中心        if (MaxRight < i + RL[i] -1) {            MaxRight = i + RL[i] -1;            pos = i;        }        if (resLen < RL[i]) {            resLen = RL[i];            resCenter = i;        }    }    return s.substr((resCenter - resLen + 1) / 2 , resLen - 1);}

時間複雜度:\(O(n)\)。在參考連結中有比較詳細的證明過程。

參考連結:1190000003914228

參考連結:http://www.cnblogs.com/grandyang/p/4475985.html

什麼是馬拉車演算法(Manacher's Algorithm)?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.