HDU 3068 最长回文 manacher 算法,基本上是O(n)复杂度
下面有别人的比较详细的解题报告:
http://wenku.baidu.com/view/3031d2d3360cba1aa811da42.html
下面贴我的代码,注释在代码中:
1 #include <cstdio> 2 #include <cstring> 3 #define N 110005 4 char a[N]; 5 char s[N<<1]; 6 int p[N<<1]; 7 int min(int a,int b) 8 { 9 return a<b?a:b; 10 } 11 int main() 12 { 13 // freopen("out.cpp","r",stdin); 14 s[0] = '#'; 15 while(scanf("%s",a) != EOF) 16 { 17 int len = strlen(a); 18 int k=1; 19 //在原字符串两个字符之间插入字符'*',左右两边也各插一个 20 //这样求回文时只需要求奇数个数的回文 21 for(int i=0; i<len; ++i) 22 { 23 s[k++] = '*'; 24 s[k++] = a[i]; 25 } 26 s[k++] = '*'; 27 int n = 2*len +1; 28 int max =0; //当以某个字符为中心求回文时延伸到右边最远的位置的序号 29 int d;//上面最远位置对应的中心位置 30 int ans =0;//记录最长回文串的长度 31 for(int i=1; i <= n; ++i) 32 { 33 if(max > i) 34 p[i] = min(max-i,p[2*d-i]); //一条线段,以位置d为中心,左边是j 35 //右边是i,这样有i+j = 2*d , j = 2*d-i;这里是核心,避免了重复计算,类似记忆化搜索 36 else 37 p[i] = 1; 38 while( s[i-p[i]] == s[i+p[i]] ) ++p[i];//小技巧,给字符串的最前面添加一个特殊字符,避免数组越界,而不是去判断 39 if(i+p[i] > max) 40 { 41 max = i+p[i]; 42 d = i; 43 } 44 if(p[i] > ans) ans = p[i]; 45 } 46 printf("%d\n",ans-1); 47 } 48 return 0; 49 }