N - 最長迴文
給出一個只由小寫英文字符a,b,c…y,z組成的字符串S,求S中最長迴文串的長度.
迴文就是正反讀都是一樣的字符串,如aba, abba等
Input
輸入有多組case,不超過120組,每組輸入爲一行小寫英文字符a,b,c...y,z組成的字符串S
兩組case之間由空行隔開(該空行不用處理)
字符串長度len <= 110000
Output
每一行一個整數x,對應一組case,表示該組case的字符串中所包含的最長迴文長度.
求最長迴文子串
1.暴力求解
對於字符串的每一個點,分別左右遍歷判斷是否滿足str[i-t]==str[i+t];
這種方法時間複雜度太高,爲N^2。
2.Manacher.(線性複雜度)
設置變量:mx(當前位置時到達最右邊的迴文串位置),len[i]數組(記錄當前迴文串長度)id(當前最長迴文串的中點位置);
manacher算法與暴力算法不同之處是利用迴文串的特性即左右對稱,做了一個預處理;
len[i]=min(mx-i,len[2*id-i]);
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
const int N=223456;
char str[N],s[N];
int len[N];
int k;
void get_s(char s[])//將字符串預處理,消除奇數串或偶串的影響,填充與字符串不同的字符;
{
k=0;
str[k++]='@';
str[k++]='#';
int len=strlen(s);
for(register int i=0;i<len;++i){
str[k++]=s[i];
str[k++]='#';
}
str[k]=0;
}
int manachar(char str[])
{
int mx=0,id; //mx初始化爲0;
int maxx=-1; //記錄最長的迴文串;
for(register int i=1;i<k;++i){
if(mx>i){ //mx在i的右邊時,len[i]爲關於id對稱點的點,即len[i-2*(i-id)和mx與i的距離最小值];
len[i]=min(mx-i,len[2*id-i]);
}
else len[i]=1; //當mx<=i時,len[i]=1;
while(str[i+len[i]]==str[i-len[i]]) ++len[i]; //拓展len[i]的長度,與暴力時一樣;
if(len[i]+i>mx){ //更新mx和id的值;
mx=len[i]+i;
id=i;
maxx=max(maxx,len[i]);
}
}
return (maxx-1);
}
int main()
{
while(~scanf("%s",s)){
get_s(s);
printf("%d\n",manachar(str));
}
return 0;
}