manacher算法--最长回文子串

来源:互联网 发布:ubuntu查看64位 32位 编辑:程序博客网 时间:2024/06/11 15:59

问题概述:输入一个字符串,输出它的最长回文子串

输入样例:                             对应输出:

abbaabcba                             5


manacher算法步骤:

①处理字符串,使所有字母左右各有一个符号"#",且只有一个,第一个字符(str[0])设为"&"最后一个字符后面改'\0'

例如:abbaabcba处理后为&#a#b#b#a#a#b#c#b#a#'\0'

目的:将奇数/偶数长度的回文子串全部转换成奇数长度

②设一个数组P[i]来记录以字符Str[i]为中心的最长回文子串向左/右扩张的长度(回文字符串长度半径,最小为1),

其中P[0]=0

例如:     & # a # b # b # a # a # b # c # b # a # \0

对应P[i]:0 1 2 1 2 5 2 1 2 5 2 1 2 1 6 1 2 1 2 1

③再增加两个辅助变量id和mx,其中id表示最大回文子串中心的位置,mx则为id+P[id]也就是最大回文子串的边界

④从第一个字符("#")开始循环,用while(str[i+p[i]]==str[i-p[i]])   p[i]++判断以i为中心回文半径,

当然如果mx>i,那么P[i]一定>=min(P[2*id-i], mx-i),直接初始化P[i]=min(P[2*id-i], mx-i)再循环以省时间

原理:http://blog.csdn.net/ggggiqnypgjg/article/details/6645824/

复杂度:O(n)


#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int p[200010];char s[100010], str[200010];int main(void){int n, i, k, ans, mx, id;while(scanf("%s", s)!=EOF){n = strlen(s);memset(str, '\0', sizeof(str));str[0] = '$';str[1] = '#';for(i=0;i<=n-1;i++)  /*步骤1*/{k = (i+1)*2;str[k] = s[i];str[k+1] = '#';}n = k+1;s[n+1] = 0;mx = ans = 0;for(i=1;i<=n;i++){p[i] = 1;if(mx>i)p[i] = min(p[2*id-i], mx-i+1);while(str[i+p[i]]==str[i-p[i]])p[i]++;if(p[i]+i-1>mx){mx = p[i]+i-1;id = i;}ans = max(ans, p[i]);}printf("%d\n", ans-1);}return 0;}



原创粉丝点击