求乙個序列的最大回文子串,我們需要需要用到manacher演算法。其作用在於能夠在o(n)的時間內求出最長回文子串,同時也能夠求出回文子串的個數。且時間效率高,**十分簡潔。
我們知道,回文子串分為奇數回文子串和偶數回文子串。由於兩種情況的處理較為麻煩,我們可以考慮在期間插入字元在簡化問題。
例如例子:aba
babc
abababc
ababab
c中,如果我們隊每相鄰的兩個數之間插入字元#,我們可以得到字串:#a#
b#a#
b#a#
b#c#
\#a\#b\#a\#b\#a\#b\#c\#
#a#b#a
#b#a
#b#c
#這樣,我們就將原問題轉化為了奇數的回文子串。對於在第i
ii個位置的字元a
ia_i
ai,我們可以求出最長的回文半徑p
ip_i
pi.那麼我們有如下結論:
那麼我們只要完成一遍namacher演算法,就能夠得到相應的p
pp陣列解決相應的問題。現在我們我們考慮如何求解p
pp陣列。
對於manacher演算法,我們需要維護乙個擴充套件到的最右邊的回文位置mxmx
mx和回文中心idid
id。即如果當前位置為i
ii,有位置i+p
[i]i+p[i]
i+p[i]
為當前的最右位置,那麼mx=
max(i
+p[i
])mx=\max(i+p[i])
mx=max(i
+p[i
]),i did
id是對應的i
ii。那麼這個演算法有什麼用呢?如圖所示:
我們根據之前對稱中心idid
id和當前位置i
ii,得到idid
id左邊與i對應的位置j
jj。j
jj的座標是:j=i
d−(i
−id)
=2×i
d−ij=id-(i-id)=2\times id-i
j=id−(
i−id
)=2×
id−i
我們會發現:
那麼在初始化時,我們就有:p[i
]=min(p
[id×
2−i]
,mx−
i)p[i]=\min(p[id\times2 -i],mx-i)
p[i]
=min(p
[id×
2−i]
,mx−
i)然後我們進行暴力擴充套件即可。
當p [i
]=p[
j]p[i]=p[j]
p[i]=p
[j]時,一次的求解複雜度為o(1
)o(1)
o(1).當p[i
]!=p
[j]p[i]!=p[j]
p[i]!=
p[j]
時,一定有p[i
]+i>mx
p[i]+i>mx
p[i]+i
>mx
則更新了mxmx
mx,而m xmx
mx的更新複雜度不超過n
nn,所以時間複雜度不超過o(n
)o(n)
o(n)
.故manacher演算法的總時間複雜度為o(n
)o(n)
o(n)
.為了防止超出了字串的範圍後繼續拓展,我們應該在字串的末尾加乙個不一樣的字元即可,當時開頭也可以加乙個不一樣的字元,但需要保證開頭結尾不同。
**如下:
#include
#include
#include
using
namespace std;
const
int n =
23000000
;int p[n]
;char s[n]
, a[n]
;void
malacher
(int n)
return;}
intmain
(void)
a[n*2+
2]='*'
;malacher(2
*n+1);
int ans =0;
for(
int i=
1;i<=n*2+
1;++i)
ans =
max(ans,p[i]-1
);cout<
return0;
}
演算法學習 manacher
沒有前置知識 解決的問題 大多數都和回文串有關 例如 字串中長度最長的回文串 演算法學習 請牢記這個目的 先來講樸素演算法 從1 n,對每個字元都從其自身開始,向兩邊遞推,如果左右兩邊字元相同,範圍 1,長度 2 這樣的複雜度是n 2的 而 manacher 的優化方式和 kmp 有所類似,都是利用...
Manacher演算法 學習筆記
首先,強烈安利一篇文章,這篇文章對於 manacher 的講解本人感覺非常到位。傳送門相信大家都知道的乙個方法 列舉字串的每乙個位置作為回文子串的對稱中心,同時向左向右擴充套件,判斷是否相等,然後每次儲存之前求取的最大回文子串長度,時間複雜度為 o n 2 在列舉時,還需要考慮對奇數回文串和偶數回文...
Manacher演算法學習筆記
manacher演算法是乙個求乙個字串中最長回文連續子串行的演算法 p3805 模板 manacher 演算法 description 求最長回文子串的長度 solution 我們先引入乙個 o n 2 的做法,列舉每個字元為回文串的中心,嘗試向兩邊擴充套件,用擴充套件的最大長度更新答案。為了下文描...