最长回文字串(hdu 3068)
原题链接http://acm.hdu.edu.cn/showproblem.php?pid=3068
查找字符串中最长的回文串,我们用到manachar算法。
要实现manachar算法我们有有两步要做
1:对字符串进行处理,把所有的字符串的长度统一化为奇数。。
1 int l=0; 2 int ans=0; 3 Ma[l++]='$'; 4 Ma[l++]='#'; 5 for(int i=0;i<len;i++) 6 { 7 Ma[l++]=s[i]; 8 Ma[l++]='#'; 9 } 10 Ma[l]=0;
例如abbba这个字符串经过处理后就变成了
$#a#b#b#b#a#
然后我们用的Mp[]表示以i为中心的(包含i这个字符)回文串半径长,然后我们就要去求Mp数组的值
假设我们扫到i+k这个位置,那么我们现在需要计算Mp[i+k],
若s[i+k]不在前面任何一个回文串中,MP[i+k]=1;
然后s[i+k]左右延伸
while(Ma[i-Mp[i]]==Ma[Mp[i]+i]) Mp[i]++;
若是s[i+k]在之前的回文串中那么Mp[s+k]就不是从1开始了,而且Mp[i]数组有一个最小值
我们设j=2*id-i;j是i关于id的对称点,下图中p数组就是Mp数组
综上所述Mp[i]=min(Mp[2*id-i],mx-i);
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 const int maxn=110000; 6 char s[maxn]; 7 char Ma[maxn*2]; 8 int Mp[maxn*2]; 9 using namespace std; 10 int manachar(int len) 11 { 12 int l=0; 13 int ans=0; 14 Ma[l++]='$'; 15 Ma[l++]='#'; 16 for(int i=0;i<len;i++) 17 { 18 Ma[l++]=s[i]; 19 Ma[l++]='#'; 20 } 21 Ma[l]=0; 22 int mx=0,id=0; 23 for(int i=0;i<l;i++) 24 { 25 if(mx>i) 26 Mp[i]=min(Mp[2*id-i],mx-i); 27 else 28 Mp[i]=1; 29 while(Ma[i-Mp[i]]==Ma[Mp[i]+i]) Mp[i]++; 30 if(i+Mp[i]>mx) 31 { 32 mx=i+Mp[i]; 33 id=i; 34 } 35 ans=max(ans,Mp[i]-1); 36 } 37 return ans; 38 } 39 int main() 40 { 41 while(scanf("%s",s)!=EOF) 42 { 43 int len=strlen(s); 44 int ans=manachar(len); 45 printf("%d\n",ans); 46 } 47 return 0; 48 }
完整的AC代码