Manacher演算法詳解

一、簡介

Manacher演算法是用來解決「最長迴文子串」的問題,它是一個時間複雜度為O(n)的演算法,比起暴力方法O(n^3)和動態規劃O(n^2)更為高效。本文將從演算法思路、代碼實現等多個方面詳細介紹Manacher演算法。

二、演算法思路

Manacher演算法的核心思想是利用已經得到的迴文中心的信息來推斷出更多的迴文中心,從而得到最長迴文子串的長度。每個迴文中心都可以向兩邊擴展,擴展出來的字元串如果仍然是迴文的,就可以得到新的迴文中心。

可以分為以下兩個步驟:

第一步:處理字元串

為了將奇數長度迴文和偶數長度迴文都統一處理,需要在每兩個字元之間插入一個符號,例如「aa」插入符號後為「#a#a#」,”123″插入符號後為「#1#2#3#」。這樣字元串的長度就變成了奇數。

第二步:計算最長迴文長度

需要維護兩個變數mx和id,其中mx表示當前在所有已經發現的迴文串中,向右端點最遠的那個迴文串的右端點的位置,id表示該迴文串的中心位置。最長迴文長度即為mx減去id。

為什麼要用mx和id?因為可以通過已經處理好的迴文串來推斷新的迴文串,這樣可以避免重複計算已經處理過的迴文串。

如何推斷新的迴文串?在已知最右邊的迴文中心的情況下,依次向右遍歷每個字元,並以該字元為中心向兩邊擴展,得到以該字元為中心的最長迴文半徑。

可能有人會問,最長迴文子串的具體值是多少呢?本演算法並沒有直接計算迴文子串的值,只是記錄了最長迴文子串的長度。如果需要得到具體的迴文子串,可以通過最長迴文子串的起點(mx-id)和長度(mx-id)計算得到。

三、代碼實現

string manacher(string s) {
    string t = "$#";
    for (int i = 0; i < s.size(); i++) {
        t += s[i];
        t += "#";
    }
    vector<int> p(t.size(), 0);
    int id = 0, mx = 0; // id是最長迴文串的中心,mx是最右邊的,迴文串能夠觸及到的最右邊的位置
    int maxLen = 0, center = 0; // maxLen是最長迴文長度,center是最長迴文中心

    for (int i = 1; i  i) {
            p[i] = min(mx - i, p[2 * id - i]);
        } else {
            p[i] = 1;
        }
        while (t[i - p[i]] == t[i + p[i]]) {
            p[i]++;
        }
        if (mx < i + p[i]) {
            id = i;
            mx = i + p[i];
        }
        if (maxLen < p[i] - 1) { // 減去插入的#字元
            maxLen = p[i] - 1;
            center = i;
        }
    }

    return s.substr((center - maxLen) / 2, maxLen);
}

四、複雜度分析

Manacher演算法的時間複雜度為O(n),其中n為字元串長度。具體分析如下:

第一步處理字元串的時間複雜度為O(n),因為需要插入2n+1個字元。

第二步計算最長迴文長度的時間複雜度為O(n),因為需要遍歷2n+1個字元並計算每個字元的迴文半徑。

所以總時間複雜度為O(n)。

五、優化

Manacher演算法有一些優化的細節,這裡列舉一下:

1、對字元串進行預處理

在字元串的開頭增加一個特殊字元,這樣就不需要在處理迴文中心的時候特判邊界情況了。同時,在每個字元之間插入一個符號(例如「#」),可以避免奇偶問題,使處理過程更為簡單。

2、使用數組p在計算迴文半徑時,儘可能復用已經得到的迴文信息

如果p[j]表示以j為中心的迴文串的長度,而i的位置在[j-p[j], j+p[j]]之間,那麼如果p[2 * j – i] >= p[j],那麼p[i]的初始值可以直接取p[2 * j – i]的值,這樣就不用從頭開始匹配了。

3、使用mx和id避免了重複計算的情況

mx表示當前在所有已經發現的迴文串中,向右端點最遠的那個迴文串的右端點的位置,而id表示該迴文串的中心位置。如果右邊的迴文串沒有超過之前計算過的迴文串右邊界,就可以避免重複計算了。

六、總結

Manacher演算法是一種高效的求解最長迴文子串的方法,時間複雜度為O(n)。通過預處理字元串、復用已有迴文信息以及使用mx和id等細節上的優化,可以進一步提高演算法的效率。

原創文章,作者:FMJDR,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/343271.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
FMJDR的頭像FMJDR
上一篇 2025-02-11 14:16
下一篇 2025-02-12 15:19

相關推薦

  • 蝴蝶優化演算法Python版

    蝴蝶優化演算法是一種基於仿生學的優化演算法,模仿自然界中的蝴蝶進行搜索。它可以應用於多個領域的優化問題,包括數學優化、工程問題、機器學習等。本文將從多個方面對蝴蝶優化演算法Python版…

    編程 2025-04-29
  • Python實現爬樓梯演算法

    本文介紹使用Python實現爬樓梯演算法,該演算法用於計算一個人爬n級樓梯有多少種不同的方法。 有一樓梯,小明可以一次走一步、兩步或三步。請問小明爬上第 n 級樓梯有多少種不同的爬樓梯…

    編程 2025-04-29
  • AES加密解密演算法的C語言實現

    AES(Advanced Encryption Standard)是一種對稱加密演算法,可用於對數據進行加密和解密。在本篇文章中,我們將介紹C語言中如何實現AES演算法,並對實現過程進…

    編程 2025-04-29
  • Harris角點檢測演算法原理與實現

    本文將從多個方面對Harris角點檢測演算法進行詳細的闡述,包括演算法原理、實現步驟、代碼實現等。 一、Harris角點檢測演算法原理 Harris角點檢測演算法是一種經典的計算機視覺演算法…

    編程 2025-04-29
  • 數據結構與演算法基礎青島大學PPT解析

    本文將從多個方面對數據結構與演算法基礎青島大學PPT進行詳細的闡述,包括數據類型、集合類型、排序演算法、字元串匹配和動態規劃等內容。通過對這些內容的解析,讀者可以更好地了解數據結構與算…

    編程 2025-04-29
  • 瘦臉演算法 Python 原理與實現

    本文將從多個方面詳細闡述瘦臉演算法 Python 實現的原理和方法,包括該演算法的意義、流程、代碼實現、優化等內容。 一、演算法意義 隨著科技的發展,瘦臉演算法已經成為了人們修圖中不可缺少…

    編程 2025-04-29
  • 神經網路BP演算法原理

    本文將從多個方面對神經網路BP演算法原理進行詳細闡述,並給出完整的代碼示例。 一、BP演算法簡介 BP演算法是一種常用的神經網路訓練演算法,其全稱為反向傳播演算法。BP演算法的基本思想是通過正…

    編程 2025-04-29
  • 粒子群演算法Python的介紹和實現

    本文將介紹粒子群演算法的原理和Python實現方法,將從以下幾個方面進行詳細闡述。 一、粒子群演算法的原理 粒子群演算法(Particle Swarm Optimization, PSO…

    編程 2025-04-29
  • Python回歸演算法算例

    本文將從以下幾個方面對Python回歸演算法算例進行詳細闡述。 一、回歸演算法簡介 回歸演算法是數據分析中的一種重要方法,主要用於預測未來或進行趨勢分析,通過對歷史數據的學習和分析,建立…

    編程 2025-04-28
  • 象棋演算法思路探析

    本文將從多方面探討象棋演算法,包括搜索演算法、啟發式演算法、博弈樹演算法、神經網路演算法等。 一、搜索演算法 搜索演算法是一種常見的求解問題的方法。在象棋中,搜索演算法可以用來尋找最佳棋步。經典的…

    編程 2025-04-28

發表回復

登錄後才能評論