Manacher演算法(馬拉車)

2021-10-12 13:56:03 字數 4344 閱讀 9083

演算法總結第三彈 manacher演算法,前面講了兩個字串相演算法——kmp和拓展kmp,這次來還是來總結乙個字串演算法,manacher演算法,我習慣叫他 「馬拉車」演算法。

相對於前面介紹的兩個演算法,manacher演算法的應用範圍要狹窄得多,但是它的思想和拓展kmp演算法有很多共通支出,所以在這裡介紹一下。manacher演算法是查詢乙個字串的最長回文子串的線性演算法。

在介紹演算法之前,首先介紹一下什麼是回文串,所謂回文串,簡單來說就是正著讀和反著讀都是一樣的字串,比如abba,noon等等,乙個字串的最長回文子串即為這個字串的子串中,是回文串的最長的那個。

下面介紹manacher演算法的原理與步驟。

首先,manacher演算法提供了一種巧妙地辦法,將長度為奇數的回文串和長度為偶數的回文串一起考慮,具體做法是,在原字串的每個相鄰兩個字元中間插入乙個分隔符,同時在首尾也要新增乙個分隔符,分隔符的要求是不在原串**現,一般情況下可以用#號。下面舉乙個例子:

manacher演算法用乙個輔助陣列len[i]表示以字元t[i]為中心的最長回文字串的最右字元到t[i]的長度,比如以t[i]為中心的最長回文字串是t[l,r],那麼len[i]=r-i+1。

對於上面的例子,可以得出len[i]陣列為:

len陣列有乙個性質,那就是len[i]-1就是該回文子串在原字串s中的長度,至於證明,首先在轉換得到的字串t中,所有的回文字串的長度都為奇數,那麼對於以t[i]為中心的最長回文字串,其長度就為2*len[i]-1,經過觀察可知,t中所有的回文子串,其中分隔符的數量一定比其他字元的數量多1,也就是有len[i]個分隔符,剩下len[i]-1個字元來自原字串,所以該回文串在原字串中的長度就為len[i]-1。

首先從左往右依次計算len[i],當計算len[i]時,len[j](0<=j第一種情況:i<=p

那麼找到i相對於po的對稱位置,設為j,那麼如果len[j]

那麼說明以j為中心的回文串一定在以po為中心的回文串的內部,且j和i關於位置po對稱,由回文串的定義可知,乙個回文串反過來還是乙個回文串,所以以i為中心的回文串的長度至少和以j為中心的回文串一樣,即len[i]>=len[j]。因為len[j]如果len[j]>=p-i,由對稱性,說明以i為中心的回文串可能會延伸到p之外,而大於p的部分我們還沒有進行匹配,所以要從p+1位置開始乙個乙個進行匹配,直到發生失配,從而更新p和對應的po以及len[i]。

第二種情況: i>p

如果i比p還要大,說明對於中點為i的回文串還一點都沒有匹配,這個時候,就只能老老實實地乙個乙個匹配了,匹配完成後要更新p的位置和對應的po以及len[i]。

manacher演算法的時間複雜度分析和z演算法類似,因為演算法只有遇到還沒有匹配的位置時才進行匹配,已經匹配過的位置不再進行匹配,所以對於t字串中的每乙個位置,只進行一次匹配,所以manacher演算法的總體時間複雜度為o(n),其中n為t字串的長度,由於t的長度事實上是s的兩倍,所以時間複雜度依然是線性的。

下面是演算法的實現,注意,為了避免更新p的時候導致越界,我們在字串t的前增加乙個特殊字元,比如說『$』,所以演算法中字串是從1開始的。

#include

using

namespace std;

const

int maxn=

1e6+10;

char str[maxn]

;//原字串

char tmp[maxn<<1]

;//轉換後的字串

int len[maxn<<1]

;//關鍵性的輔助陣列

intinit

(char

*st)

tmp[

2*len+1]

='#'

; tmp[

2*len+2]

='$'

;//字串結尾加乙個字元,防止越界

tmp[

2*len+3]

=0;return

2*len+1;

//返回轉換字串的長度,一定為奇數

}//manacher演算法計算過程

intmanacher

(char

*st,

int len)

ans=

max(ans,len[i]);

}return ans-1;

//返回len[i]中的最大值-1即為原串的最長回文子串長度

}

演算法總結第三彈 manacher演算法,前面講了兩個字串相演算法——kmp和拓展kmp,這次來還是來總結乙個字串演算法,manacher演算法,我習慣叫他 「馬拉車」演算法。

相對於前面介紹的兩個演算法,manacher演算法的應用範圍要狹窄得多,但是它的思想和拓展kmp演算法有很多共通支出,所以在這裡介紹一下。manacher演算法是查詢乙個字串的最長回文子串的線性演算法。

在介紹演算法之前,首先介紹一下什麼是回文串,所謂回文串,簡單來說就是正著讀和反著讀都是一樣的字串,比如abba,noon等等,乙個字串的最長回文子串即為這個字串的子串中,是回文串的最長的那個。

下面介紹manacher演算法的原理與步驟。

首先,manacher演算法提供了一種巧妙地辦法,將長度為奇數的回文串和長度為偶數的回文串一起考慮,具體做法是,在原字串的每個相鄰兩個字元中間插入乙個分隔符,同時在首尾也要新增乙個分隔符,分隔符的要求是不在原串**現,一般情況下可以用#號。下面舉乙個例子:

manacher演算法用乙個輔助陣列len[i]表示以字元t[i]為中心的最長回文字串的最右字元到t[i]的長度,比如以t[i]為中心的最長回文字串是t[l,r],那麼len[i]=r-i+1。

對於上面的例子,可以得出len[i]陣列為:

len陣列有乙個性質,那就是len[i]-1就是該回文子串在原字串s中的長度,至於證明,首先在轉換得到的字串t中,所有的回文字串的長度都為奇數,那麼對於以t[i]為中心的最長回文字串,其長度就為2*len[i]-1,經過觀察可知,t中所有的回文子串,其中分隔符的數量一定比其他字元的數量多1,也就是有len[i]個分隔符,剩下len[i]-1個字元來自原字串,所以該回文串在原字串中的長度就為len[i]-1。

首先從左往右依次計算len[i],當計算len[i]時,len[j](0<=j第一種情況:i<=p

那麼找到i相對於po的對稱位置,設為j,那麼如果len[j]

那麼說明以j為中心的回文串一定在以po為中心的回文串的內部,且j和i關於位置po對稱,由回文串的定義可知,乙個回文串反過來還是乙個回文串,所以以i為中心的回文串的長度至少和以j為中心的回文串一樣,即len[i]>=len[j]。因為len[j]如果len[j]>=p-i,由對稱性,說明以i為中心的回文串可能會延伸到p之外,而大於p的部分我們還沒有進行匹配,所以要從p+1位置開始乙個乙個進行匹配,直到發生失配,從而更新p和對應的po以及len[i]。

第二種情況: i>p

如果i比p還要大,說明對於中點為i的回文串還一點都沒有匹配,這個時候,就只能老老實實地乙個乙個匹配了,匹配完成後要更新p的位置和對應的po以及len[i]。

manacher演算法的時間複雜度分析和z演算法類似,因為演算法只有遇到還沒有匹配的位置時才進行匹配,已經匹配過的位置不再進行匹配,所以對於t字串中的每乙個位置,只進行一次匹配,所以manacher演算法的總體時間複雜度為o(n),其中n為t字串的長度,由於t的長度事實上是s的兩倍,所以時間複雜度依然是線性的。

下面是演算法的實現,注意,為了避免更新p的時候導致越界,我們在字串t的前增加乙個特殊字元,比如說『$』,所以演算法中字串是從1開始的。

Manacher 馬拉車演算法

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

馬拉車演算法manacher

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

Manacher演算法 馬拉車

於 馬拉車的解決的問題 給定字串s,求s中的最長回文子串?解釋 回文串就是正讀反讀都一樣的字串,比如奇回文串 bab 偶回文串 noon 馬拉車演算法步驟 index01 2345 6789 1011 1213 char 1 2 2 1 2 2 r121 2521 6123 21規律 最大半徑減1等...