Manacher演算法 馬拉車

2022-02-27 05:18:58 字數 2659 閱讀 1444

**於:

馬拉車的解決的問題:

給定字串s,求s中的最長回文子串?

解釋:回文串就是正讀反讀都一樣的字串,比如奇回文串(bab)、偶回文串(noon)。

馬拉車演算法步驟:

index01

2345

6789

1011

1213

char$#

1#2#

2#1#

2#2#

r121

2521

6123

21

規律①:最大半徑減1等於最長回文串的長度

看上面那個例子,以中間的 『1』 為中心的回文子串 「#2#2#1#2#2#」 的半徑是6,而未新增#號的回文子串為 「22122」,長度是5,為半徑減1。這是個普遍的規律麼?我們再看看之前的那個 「#b#o#b#」,我們很容易看出來以中間的 『o』 為中心的回文串的半徑是4,而 "bob"的長度是3,符合規律。再來看偶數個的情況 「noon」,新增#號後的回文串為 「#n#o#o#n#」,以最中間的 『#』 為中心的回文串的半徑是5,而 「noon」 的長度是4,完美符合規律。所以我們只要找到了最大的半徑,就知道最長的回文子串的字元個數了。只知道長度無法定位子串,我們還需要知道子串的起始位置。

規律②:最長回文字元的起始位置是中間位置減去半徑在除以2

我們還是先來看中間的 『1』 在字串 「#1#2#2#1#2#2#」 中的位置是7,而半徑是6,貌似 7-6=1,剛好就是回文子串 「22122」 在原串 「122122」 中的起始位置1。那麼我們再來驗證下 「bob」,「o」 在 「#b#o#b#」 中的位置是3,但是半徑是4,這一減成負的了,肯定不對。所以我們應該至少把中心位置向後移動一位,才能為0啊,那麼我們就需要在前面增加乙個字元,這個字元不能是#號,也不能是s中可能出現的字元,所以我們暫且就用美元號吧,畢竟是博主最愛的東西嘛。這樣都不相同的話就不會改變p值了,那麼末尾要不要對應的也新增呢,其實不用的,不用加的原因是字串的結尾標識為 『\0』,等於預設加過了。那此時 「o」 在"$#b#o#b#"中的位置是4,半徑是4,一減就是0了,貌似沒啥問題。我們再來驗證一下那個數字串,中間的 『1』 在字串"$#1#2#2#1#2#2#"中的位置是8,而半徑是6,這一減就是2了,而我們需要的是1,所以我們要除以2。之前的 「bob」 因為相減已經是0了,除以2還是0,沒有問題。再來驗證一下 「noon」,中間的 『#』 在字串"$#n#o#o#n#"中的位置是5,半徑也是5,相減並除以2還是0,完美。所以,最長回文字元的起始位置是中間位置減去半徑在除以2。

關於p陣列的求解,需要建立兩個輔助變數mx和id,id表示回文串的中心位置下標,mx表示回文串右邊最大半徑下標,所以mx = id + p[id]

接下來就是求p[i],當然這也是演算法中最重要的部分:

p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;
注:2 * id - i表示 i 關於 id 對稱的座標點j。因為 j 到 id 之間到距離等於 id 到 i 之間到距離(id - j = i - id),所以j = 2 * id - i

如果 mx > i, 則 p[i] = min( p[2 * id - i] , mx - i );否則,p[i] = 1。

①: 在mx > i的前提下,若p[j] < mx - i,表示以 s[j] 為中心的回文子串包含在以 s[id] 為中心的回文子串中,由於 i 和 j 對稱,以 s[i] 為中心的回文子串必然包含在以 s[id] 為中心的回文子串中,所以必有 p[i] = p[j]。

②: 在mx > i的前提下,若p[j] >= mx - i表示以 s[j] 為中心的回文子串不一定完全包含於以 s[id] 為中心的回文子串中,也就是說p[j]表示的回文串半徑超過mx對稱點的座標了,那麼此時不能利用對稱性了,但我們一定可以擴充套件到 mx 的,至於mx之後的部分我們任然需要匹配了。

③: 在mx <= i的前提下,p[i] = 1,因為此時我們需要通過中心擴充套件法一步一步擴充套件半徑就行了。

關於p[i] = mx > i ? min(p[2 \* id - i], mx - i) : 1;的更好理解,大家可看:一文讓你徹底明白馬拉車演算法此文中的三種特殊情況!

#include #include #include using namespace std;

string mannacher(string s)

//更新最大回文子串的資訊,半徑及中間位置

if(reslen

}//最長回文子串長度為半徑-1,起始位置為中間位置減去半徑再除以2

return s.substr((rescenter-reslen)/2,reslen-1);

}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...