馬拉車演算法 manacher

2022-05-11 16:07:04 字數 1673 閱讀 4585

更好的閱讀體驗

個人感覺和kmp也許有異曲同工之妙。

[button color="warning" icon="" url="" type=""]模板題傳送門[/button]

首先,我們的目標是求出最長回文子串的長度

暴力相信大家都會,先是列舉l和r然後o(n)判斷每個子串是否是回文串,總時間複雜度\(o(n^3)\)。

稍微優化一下,列舉中間點mid,貪心地向兩端擴充套件找到最長的\(len[i]\),即以i為回文串中心的最大擴充套件長度。當然,我們發現這樣只能處理回文串長度為奇數的情況。所以對於這個暴力,我們有了乙個新思路:在兩個相鄰字元之間插入乙個不會出現的字元。

比如aabba,我們把它變成#a#a#b#b#a#,這樣每個點向兩邊擴充套件出的就一定是奇數長度的\(len[i]\)了。於是這個暴力的時間複雜度就是\(o(n^2)\)。下面所使用的字串也是經過了這樣的變換的。

這也正開啟了馬拉車演算法的大門。

眾所周知,對暴力演算法的優化是對重複計算的優化以及已知資訊的利用

先來看重複的計算。

在上面\(o(n^2)\)的演算法中,我們對很多子串進行了重複搜尋,最明顯的就是,假設i和j都在同乙個回文子串內並且關於中心對稱,那麼\(len[j]>=len[i]\)。這是顯然的。

於是我們考慮設定乙個變數\(mid\),表示上面那個回文子串的中心,\(mr(maxright)\)表示這個回文子串的右端點。

哦對了,這個回文子串是當前右端點最大的回文子串,所以叫做maxright。

當我們目前遍歷到的i是小於mr的時候,即下圖這種情況。

如圖,我們找到i的對稱點i',發現可以用2*mid-i得到,於是len[i]=len[mid*2-i],但是這個對稱只在我們以mid為重心的回文串中可以用,所以i+len[i]<=mr,len[i]<=mr-i,綜合,len[i]=min(len[mid*2-i],mr-i)

接下來是另一種情況,也就是i在mr的右邊,i>=mr。

此時,我們沒有多餘的資訊可以利用了,只能以i為重心開始和上面說的一樣暴力地拓展找len[i],那麼此時我們的i就是新的mid,找到的i+len[i]就是新的mr。

那麼這樣的時間複雜度為什麼是o(n)的呢?

首先考慮i最令人迷惑的就是i>=mr的時候。

看似這樣while去找新的len是非常浪費時間的,但是我們在這一步擴充套件了mr,並且mr會且只會從1被擴充套件到n,所以mr的擴充套件總共是o(n)的,mr不擴充套件的時候也就是i於是總的時間複雜度就是o(n)。

模板題**;

#include#define max(a,b) (a>b?a:b)

#define reg register

using namespace std;

const int n=2.2e7+10;

char d[n];

int hw[n],n;

void read()

void manacher()

}int main()

Manacher 馬拉車演算法

給定乙個字串,求出其的最長回文子串 乙個將時間複雜度優化到o n 的演算法 暴力演算法,但不是純暴力,即按照做過的事情不再去做來優化 我們知道,乙個回文串要麼是奇數的串 aba 要麼是偶數的串 abba 可以看出,乙個回文串有乙個對稱軸 對於奇數串aba來說,對稱軸就是b 而對於偶數串abba來說,...

Manacher演算法(馬拉車)

演算法總結第三彈 manacher演算法,前面講了兩個字串相演算法 kmp和拓展kmp,這次來還是來總結乙個字串演算法,manacher演算法,我習慣叫他 馬拉車 演算法。相對於前面介紹的兩個演算法,manacher演算法的應用範圍要狹窄得多,但是它的思想和拓展kmp演算法有很多共通支出,所以在這裡...

馬拉車演算法manacher

1.預處理解決奇回文和偶回文問題 比如 str bcbaa 在每個字元的開頭,結尾和中間插入乙個特殊字元 來得到乙個新的字串 b c b a a 這樣對於原來字串中的奇回文 bcb 來說,在新的字串中變成了 b c b 還是奇回文,只是回文串長度從3變成了7 注意 中 i 1 0,與1按位與,如果i...