hdu3068
题意:给出一个字符串,计算其中的最长回文长度
这题字符串长度给到10的5次方,简单的枚举不行。采用manacher算法则可以在O(n)的时间内得出答案。
manacher算法理解:
工具:1、定义了一个数组 r[ i ] 记录的是以i为中心向最左边(或者最右边)的最长回文长度,即回文的半径。
2、定义整数形的id,记录到目前为止记录的回文所能到的最右边的回文中心。
3、定义一个maxlen记录最长回文长度
预处理:在原来的字符串中插入“#”;作用:使插入后的字符串变成奇数长度,便于求出回文中心。
分析:
1、i < r [ id ] + id;
此时分两种:
1 、r [ i ] = r [ j ] ( j 为 i 关于 id 的对称点 );
2、r [ i ] 最小为 r [ id ] +id-i;
再左右遍历;
2、i >=r [ id ]+ id;
这时只能左右遍历了。
https://www.cnblogs.com/z360/p/6375514.html
具体在这个博客有更详细的分析。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<algorithm> using namespace std; #define MAX 110002 int r[2*MAX]; string s,ss; int init() { int len=s.size(); ss+='!';//防止溢出 ss+='#'; for(int i=0;i<len;i++) { ss+=s[i]; ss+='#'; } cout<<ss; return ss.size(); } int manacher(int len) { int id=0; int maxlen=0; for(int i=2;i<len;i++) { if(i<r[id]+id) r[i]=min(r[2*id-i],r[id]+id-i); else r[i]=1; while(ss[i+r[i]]==ss[i-r[i]])r[i]++; if(r[i]+i>r[id]+id)id=i; maxlen=max(maxlen,r[i]); } return maxlen-1;//记得减一 } int main() { while(cin>>s) { memset(r,0,sizeof(r)); ss=""; int len=init(); printf("%d\n",manacher(len)); getchar(); } }