最長迴文串的求解,顧名思義,給函數一個字符創str,在該字符串中找到最長的迴文,例如:
str=“abababc”,其中單個字母a,b,c都可以看做迴文,其長度爲1;aba,bab也是迴文,長度爲3;ababa,babab,也是迴文,其長度爲5。我們可以發現在一個字符串中有許多不同長度的迴文,而我們的任務就是找到最長的迴文的長度值,即5。
最直接的方法就是以每個字符爲中心向左右兩邊,同時擴展尋找以該字符爲中心的最長迴文。事實上,manacher算法的核心思想也是基於此操作的,不一樣的是該方法使用了動態規劃的思想,從左往右一次求解以字符爲中心的最長迴文,每次的求解都是建立在該字符往左的已知結論上。具體的原理可以參考鏈接處,
http://blog.csdn.net/xingyeyongheng/article/details/9310555
注意,Manacher方法的時間複雜度是O(n),n是字符串中的字符總數。
針對hiho上的最長迴文問題的代碼如下
<span style="font-size:14px;">#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N_MAX=2000040;
int rad[N_MAX];
char str[N_MAX];
int len;
int Solve()
{
//fill(rad,rad+N_MAX,0);
scanf("%s",str);
len=strlen(str);
if(len==0)
return 0;
for(int i=2*len+1;i>1;i-=2){ //對源字符串變形,將“ababc”變爲“$#a#b#a#b#c#”,後續計算過程中從左數第一“#”開始計算rad,下標i從1開始
str[i]='#';
str[i-1]=str[i/2-1];
}
str[0]='$';str[1]='#';str[2*len+2]='\0';
/*for(int i=0;i<strlen(str);i++)
printf("%c",str[i]);
printf("\n");*/
int id(0),mx(0),mxrd(0); //Manacher算法
for(int i=1;i<=2*len+1;i++){
rad[i]=mx>i?min(rad[2*id-i],mx-i):1; //在最大邊界外,rad[i]初始值爲1,否則取i關於id對稱處的rad,或者id的最大右邊界mx減i
while(str[i+rad[i]]==str[i-rad[i]])rad[i]++;
if(rad[i]+i>mx){
id=i;
mx=i+rad[i];
}
if(mxrd<rad[i])
mxrd=rad[i];
//printf("%d",rad[i]);
}
return mxrd-1; //rad[i]-1剛好等於對應的迴文子字符串的長度,i可能對應一個字母,也可能對應#
}
int main()
{
int num;
scanf("%d",&num);
fflush(stdin);
while(num--){
printf("%d\n",Solve());
}
return 0;
}</span>
做了一道Leetcode上的longest Palindrome substring的題,明白了改變原字符串爲加‘#’形式的重要性,即下面的注意事項:
一定要在首位各加一個作爲開始和結尾的標誌,並且必須不同,例如開頭是‘$’,那麼結尾可以用‘\0’。總之,不能一樣。因爲你在尋找回文,如果一樣了,那麼我們豈不是暗中加長了迴文的可能性。