manacher算法--最长回文子串

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

输入样例:                             对应输出:

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
#include
#include
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;
		str[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;
}



你可能感兴趣的:(字符串)