马拉车
主要是想得到p数组
对于p[i]有,以i为中心的回文串起始坐标为(i-p[i])/2;长度为 p[i]-1;
#include<iostream> #include<string.h> #include<algorithm> using namespace std; char s[1000]; char s_new[2000]; int p[2000]; int Init() { int len = strlen(s); s_new[0] = '$'; s_new[1] = '#'; int j = 2; for (int i = 0; i < len; i++) { s_new[j++] = s[i]; s_new[j++] = '#'; } s_new[j] = '\0'; return j; } int Manacher() { int len = Init(); //取得新字符串长度并完成向s_new的转换 int maxLen = -1; //最长回文长度 int check=0; //最长回文串的起始位置 int id; int mx = 0; for (int i = 1; i < len; i++) { if (i < mx) p[i] = min(p[2 * id - i], mx - i); else p[i] = 1; while (s_new[i - p[i]] == s_new[i + p[i]]) //不需边界判断,因为左有'$',右有'\0' p[i]++; //我们每走一步i,都要和mx比较,我们希望mx尽可能的远,这样才能更有机会执行if (i < mx)这句代码,从而提高效率 if (mx < i + p[i]) { id = i; mx = i + p[i]; } if(p[i]-1>maxLen){ maxLen=p[i]-1; check=(i-p[i])/2; } } //输出最长字符串 // for(int i=check;i<check+maxLen;i++){ // cout<<s[i]; // } // cout<<endl; return maxLen; } int main() { while (printf("请输入字符串:\n")) { scanf("%s", s); printf("最长回文长度为 %d\n\n", Manacher()); } return 0; }
另一个版本,求最大回文前缀和最长回文后缀 s1 里面存放的是最长回文前缀的长度,s2 存的是最长后缀的长度 截取 方法
if(s1>s2)ans1=s.substr(0,s1); //前缀
else ans1=s.substr(n-s2); // 后缀
char tmp[maxx]; int len[maxx]; int s1,s2; void Manacher(string s) { tmp[0]='$'; tmp[1]='#'; int t=s.size(); for(int i=0;i<2*t+5;i++)len[i]=0; for(int i=1;i<=t;i++) { tmp[2*i]=s[i-1]; tmp[2*i+1]='#'; } tmp[2*t+2]='\0'; int mx=0; int mid; for(int i=1;tmp[i];i++) { if(i<mx)len[i]=min(len[2*mid-i],mx-i); else len[i]=1; while(tmp[i-len[i]]==tmp[i+len[i]])len[i]++; if(len[i]+i>mx) { mx=len[i]+i; mid=i; } int l=len[i]-1; if(i%2==0) { l=(l-1)/2; int p=i/2; if(p-l==1)s1=max(s1,len[i]-1); if(p+l==t)s2=max(s2,len[i]-1); } else { l=l/2; int p=(i-1)/2,q=(i+1)/2; if(p-l+1==1)s1=max(s1,len[i]-1); if(q+l-1==t)s2=max(s2,len[i]-1); } } }
rush!