Manacher入门
寫在前面
manachermanachermanacher比想象中好理解得多
至少它給了我學習字符串的信心
能干啥
manachermanachermanacher,中文馬拉車(您別說,這名字還挺形象),主要用于計算字符串每一個位置為對稱中心的回文串長度(等價于個數(shù))
包括偶回文,即長度為偶數(shù)的回文串
算法流程
考慮下面的問題:給一個字符串,求最長回文子串
我會暴力!
枚舉判斷O(n3)O(n^3)O(n3)
我會優(yōu)化!
考慮到以ccc為中心,acbacbacb不是回文串,左右怎么接都不是回文串
所以可以枚舉中間點(偶回文判斷一下即可),然后向兩邊拓展
復雜度O(n2)O(n^2)O(n2)
我會玄學!
O(n2)O(n^2)O(n2)還不夠 不符合字符串算法均為線性復雜度公理
在此基礎(chǔ)上繼續(xù)優(yōu)化
我們記錄maxrmaxrmaxr為目前找到的回文串右端點的最右的位置 pospospos為這個回文串的對稱中心
開一個數(shù)組pip_ipi?表示回文半徑(和其他文章不同,本文回文半徑指一個端點到中心的距離,即直接相減)
回文串最本質(zhì)的特征是什么?左右關(guān)于中心對稱。
如果一個回文串對稱中心的一側(cè)有另一個回文子串,那么對稱過去也有一個相同長度的回文子串
黃色部分完全一致,這就是manacher的核心
(先不考慮偶回文)
① i<maxri<maxri<maxr(取不取等于無所謂)
設(shè)j,ij,ij,i關(guān)于pospospos對稱 即j=pos?2?ij=pos*2-ij=pos?2?i
根據(jù)上面的推導,令pi=pjp_i=p_jpi?=pj?即可
當然如果jjj為中心的最長回文左端點越界了
那就不能保證上面的性質(zhì)(實際上可以保證不成立),所以要和j?maxlj-maxlj?maxl(即maxr?imaxr-imaxr?i)取minminmin。
jjj越界時還需要讓iii繼續(xù)拓展。當然為了刷短代碼減少討論,都拓展一下好了
②i≥maxri \geq maxri≥maxr
啥都不能保證,直接暴力擴展
綜上:
然后……對,沒了,就三行。
這就是manachermanachermanacher的全過程,復雜度O(n)O(n)O(n),后面有證明
實現(xiàn)
上面沒有討論偶回文,主要是轉(zhuǎn)化過程比較難看,容易使人喪失信心。
其實也不難。只需要在字符兩兩之間加一個字符,如‘#’;然后首尾也加上‘#’,再在開頭加一個標識符防止越界。注意要和之前的不同,如‘@’
這樣偶回文可以看做中心是‘#’的回文
普及T1模擬水平
這樣處理后,所有回文串左右端點都是‘#’,然后就可以跑了
證明
什么?不是只改了一個地方嗎?怎么變O(n)O(n)O(n)了?
回顧整個流程,真正暴力拓展的時候要么jjj左端點越界,要么iii越界(jjj左端點沒越界時,根據(jù)反證法,iii實際上無法拓展)
jjj左端點越界時,iii右端點出生點就在maxrmaxrmaxr,再拓展就超出去了
也就是說,每次暴力拓展,都意味著maxrmaxrmaxr更新,而maxrmaxrmaxr只會往右跑
換一個角度,實際上暴力拓展是把maxrmaxrmaxr推到最右邊,次數(shù)是O(n)O(n)O(n)的
所以總復雜度是O(n)O(n)O(n)的
代碼
#include <iostream> #include <cstdio> #include <cstring> #define MAXN 1000005 using namespace std; char s[MAXN],ss[MAXN]; int pos,maxr; int p[MAXN]; int main() {scanf("%s",s+1);int n=strlen(s+1);for (int i=1;i<=n;i++) ss[i<<1]=s[i],ss[(i<<1)|1]='#';n=(n<<1)|1,ss[0]='@',ss[1]='#';strcpy(s,ss);for (int i=1;i<=n;i++){if (i<maxr) p[i]=min(p[(pos<<1)-i],maxr-i);while (s[i-p[i]-1]==s[i+p[i]+1]) ++p[i];if (i+p[i]>maxr) maxr=i+p[i],pos=i;}return 0; }由于所有位置為中心的最長回文串左右端點都是‘#’
回文串長度leni=2pi+1?12=pilen_i= \frac {2p_i+1-1}{2} = p_ileni?=22pi?+1?1?=pi?
然后用來搞事情就可以了
總結(jié)
以上是生活随笔為你收集整理的Manacher入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 头部会产生很小的颤动声音是怎么回事?
- 下一篇: 耳边总感觉有人在说话怎么回事?