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 }
View Code

 

posted on 2013-08-01 16:02  allh123  阅读(191)  评论(0编辑  收藏  举报

导航