這個演算法。和原先學習的kmp都是處理字串的。只不過麻雀是專門針對回文串的。我是最近cf補題的時候碰到這個演算法的。特此記錄一下。說實話。原先學資料結構的時候學的kmp。現在應該完全忘光了把。。啊哈哈。明天再補補。
舉個例子:
回文串分為奇回文和偶回文。奇回文的中心是中間的字元。偶回文的中心是兩個字元中間的位置。不好同一處理。
所以我們加如下操作。比如aabbaa
增加為#a#a#b#b#a#a#
這樣不管是奇回文還是偶回文都是字元啦。偶回文是#。奇回文還是原來的。
我們用陣列p儲存當前下標index作為中心時的回文序列長度半徑。
所以我們以當前下標index為中心的回文串的最長長度就是p[i] - 1(這個地方不證明了。自己隨便舉幾個例子就明白了)
mx記錄當前已操作序列的最右的回文邊界。就是最長的回文序列的最右邊的地方。
id記錄最長回文序列的中心位置。
當我們遍歷到i時。求p[i]
我們找到i的對稱點j。這個地方的下標很簡單求出來。(id - (i - id))即可
如圖所示mx的對稱點也標出來了。上面解釋了。mx是最優邊界。id是最長回文串的中心。
p[j]我們已經求出來了。
本演算法的核心**:
上面的p[2*id - i]就是p[j];
我們討論一下p[j]的大小。
如果p[j]的回文串只有這麼長。
也就是沒有大於mx - i的長度
圖中標記的橙色部分相等。。這個簡單。
也就是以j為中心得回文串沒有超過這個長度。
因為對稱。所以此時我們賦值p[i] = p[j];這個是此時p[i]的最小長度。就在這個地方節約時間的。
至於p[i]的值有沒有可能更長。我們後面暴力跑一遍就行。
如果p[j]的回文串大於了這個長度。
也就是這樣:
已經超過了mx的對稱點的長度。
那我們只能將p[i]賦值為mx - i
因為這個mx - i是我們現在已知的最小長度。
因為mx對稱點左邊的字元和mx右邊的字元不等呀。不然mx肯定不在當前位置了。。
之後我們暴力跑一遍判斷即可。
我當時在想為啥這兩部分的p是一一對稱的。
傻坐在那想了半天。。
後來舉了個例子畫了個圖就知道了。
因為mx和mx對稱點範圍內就是我們求得最長回文呀。id左邊和id右邊肯定是一一對稱的呀。。。害~
上面解釋完了就應該很好理解了。
然後我們在製作新的字串的時候注意邊界位置。
第乙個字元初始化為$
最後乙個字元就是結束標誌』\0』就行。避免溢位。
時間複雜度控制在o(n)範圍
棒~模板**:
我最後輸出的是最長的回文串的長度。
#include
using
namespace std;
const
int n =
2e7+10;
string s;
char ss[n]
;int p[n]
;int
init()
//形成新的字串
ss[i]
='\0'
;return i;
}int
manacher()
else
while
(ss[i - p[i]
]== ss[i + p[i]])
if(mx < i + p[i]
) maxx =
max(maxx, p[i]-1
);}return maxx;
}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...