算法原理
最長回文字符串包括奇數(shù)長的和偶數(shù)長的,求的時(shí)候都要分情討論,Manacher算法做了一個(gè)簡單的處理爷狈,很巧妙地把奇數(shù)長度回文串與偶數(shù)長度回文串統(tǒng)一考慮侍芝,也就是在每個(gè)相鄰的字符之間插入一個(gè)分隔符,串的首尾也要加,當(dāng)然這個(gè)分隔符不能再原串中出現(xiàn)宪萄,一般可以用‘#’字符。
這樣一來榨惰,原來的奇數(shù)長度回文串還是奇數(shù)長度拜英,偶數(shù)長度的也變成以‘#’為中心奇數(shù)回文串了。
其次給每個(gè)字符串首部加一個(gè)題目中不會(huì)出現(xiàn)的字符读串,避免處理越界問題聊记。(一般加’$’)
如圖字符串就是通過
算法預(yù)處理得到的新串
數(shù)組記錄的以
為中間
字符的回文串向右能匹配的最大長度(包括S[i]這個(gè)字符).
當(dāng)不是所加字符‘#’時(shí),
就是字符串長度了
假設(shè)以i為中心的回文串長度為
,因?yàn)?img class="math-inline" src="https://math.jianshu.com/math?formula=p%5B%20i" alt="p[ i" mathimg="1">]記錄以
為中間字符的回文串向右能匹配的長度恢暖,所以有
又因?yàn)榇藭r(shí)串中加了其他字符#排监,以為中心的回文串一定是以#開頭和結(jié)尾的,以#為中間字符的就是長度為偶數(shù)的杰捂,以非#號(hào)為中間字符的就是長度為奇數(shù)的舆床,例如“#b#b#”或“#b#a#b#”所以減去最前或者最后的‘#’字符就是原串中長度的2倍,即原串長度為
嫁佳,化簡的
挨队。
算法實(shí)現(xiàn)
算法實(shí)現(xiàn)就是要找出
數(shù)組,如何找出
數(shù)組是關(guān)鍵.
首先從左往右依次計(jì)算
,當(dāng)計(jì)算
時(shí)蒿往,
已經(jīng)計(jì)算完畢盛垦。設(shè)
為之前計(jì)算中最長回文子串的右端點(diǎn)的最大值,并且設(shè)取得這個(gè)最大值的位置為
瓤漏,分兩種情況:
情況1:
那么找到相對(duì)于
的對(duì)稱位置腾夯,設(shè)為
,那么如果
因?yàn)?img class="math-inline" src="https://math.jianshu.com/math?formula=i%2Bj%3D2*id" alt="i+j=2*id" mathimg="1">,能向左匹配的最左端點(diǎn)的坐標(biāo)是
所以可知,所以可知
向如下圖:
那么說明以為中心的回文串一定在以
為中心的回文串的內(nèi)部蔬充,且
和
關(guān)于位置
對(duì)稱,那么意味著以
為中間字符的回文串能向右匹配最右端點(diǎn)沒有超過
蝶俱。由回文串的定義可知,一個(gè)回文串反過來還是一個(gè)回文串饥漫,所以以i為中心的回文串的長度至少和以j為中心的回文串一樣榨呆,所以
。
- 如果
,由對(duì)稱性庸队,說明以
為中心的回文串可能會(huì)延伸到
之外积蜻,而大于
的部分我們還沒有進(jìn)行匹配,所以要從
位置開始一個(gè)一個(gè)進(jìn)行匹配彻消,直到發(fā)生失配浅侨,從而更新
和對(duì)應(yīng)的
以及
。
雖然p[j]>mx-i,但是可以保證的是這一段是跟
是一樣的证膨,說明以s[i]為中心的回文串至少有
這么長
情況2:
如果i比mx還要大,說明對(duì)于中點(diǎn)為i的回文串還一點(diǎn)都沒有匹配鼓黔,這個(gè)時(shí)候央勒,就只能老老實(shí)實(shí)地一個(gè)一個(gè)匹配了不见,匹配完成后要更新的位置和對(duì)應(yīng)的
以及
。
int len=strlen(s);
int mx=0;
int id=0;
int res=-1;
for(int i=len;i>=0;i--)
{
s[i*2+2]=s[i];
s[i*2+1]='#';
}
s[0]='$';//加上特殊字符防止越界
for(int i=0;i<=2*len+1;i++)
{
if(mx>i)//mx<i的情況
{
p[i]=min(p[2*id-i],mx-i);//比較p[j]大還是mx-i大崔步,取小的
}
else//如果i>=mx稳吮,要從頭開始匹配
{
p[i]=1;
}
while(s[i-p[i]]==s[i+p[i]])//一個(gè)一個(gè)比較
{
p[i]++;
}
if(p[i]+i>mx))//若新計(jì)算的回文串右端點(diǎn)位置大于mx,要更新id和mx的值
{
mx=p[i]+i;
id=i;
}
res=max(res,p[i]-1);
}