首页 > 代码库 > Manacher 最长回文串问题

Manacher 最长回文串问题

  有人问你,一个字符串中最长的回文字串是谁?

  作为一个 2B 青年, 一年前的我会这样回答:暴力枚举每个字串,判断合法与否?

  ╮(╯▽╰)╭ 就是没什么戏。。。。

  后来,在机房的一个大牛的介绍下,我知道了 Manacher 算法。

  。。。。。。。。。。。。。。。。。。。。。。。。。。。。

  其实 Manacher 和 KMP 是非常之像的。

  令 rad[i] 表示以 第 i 个字符为中心的回文字串的半径长度。

  那么我们考虑一下当前最远拓展到 j 编号为 rad[k],那么我们当前要计算的 rad[i] 有如下几种情况:

  i 关于 k 对称的字符为 t = k + k - i. 那么如果 i + rad[t] < j 那么 rad[i] = rad[t]

                      若 i + rad[t] >= j我们必须 暴力拓展 直到失配为止

  这样子的话,复杂度是 O(n) 的。比暴力好了很多。

  我们看一下代码:

    

 1 #include<cstdlib> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define maxn 310100 6 using namespace std; 7 char s[maxn],Ma[maxn]; 8 int rad[maxn],Max,L,kase; 9 void manacher(char s[],int L)10 {11     memset(rad,0,sizeof(rad));12     Max = 0;13     int len = 0;14     Ma[len++] = #;15     for(int i=0;i<L;++i){16         Ma[len++] = s[i];17         Ma[len++] = #;18     }19     int i,j,k;20     for(int i=1,j=0;i<len;i+=k){21         while(Ma[i-j-1] == Ma[i+j+1] && i-j-1>=0 && i+j+1<len)22             j++;23         rad[i] = j;24         Max = max(rad[i],Max);25         for(k=1;k<=rad[i] && rad[i]<rad[i-k]+k;++k)26             rad[i+k] = min(rad[i-k],rad[i]-k),27             Max = max(Max,rad[i+k]);28         j = max(j-k,0);29     }30 }31 int main()32 {33     freopen("manacher.in","r",stdin);34     freopen("manacher.out","w",stdout);35     while(scanf("%s",s)!=EOF){36         if(s[0] == E)break;37         L = strlen(s);38         manacher(s,L);39         printf("Case %d: %d\n",++kase,Max);40     }41     return 0;42 }        

 

Manacher 最长回文串问题