Manacher算法

Manacher算法的应用

求出字符串的最长回文子串。

Manacher算法的流程

1、插入特殊字符

因为回文串的长度可能是奇数或偶数,为了不考虑这么多情况,就插入一些特殊字符。
比如:abcddcba
插入后变成:#a#b#c#d#d#c#b#a#
所以可以将问题转化成求长度为奇数的回文串。

2、求出每一位为中心的最长回文子串

pip_i为以i为中心的最长回文子串。
如何求pip_i
通过前面的信息,首先要求出Maxright和pos。
Maxright为前面所求的回文字符串中最靠右的右端点,pos为Maxright所对应的中心点。
分两种情况讨论:

  1. i在Maxright的左边。先找到i关于pos的对应点j(j=2posij=2*pos-i)。如果将j的回文串复制到i,保证的回文长度为min(p[j],Maxrighti)\min (p[j],Maxright-i),在这个基础上尽量往两边扩展。
  2. 否则,保证的回文长度为1,在这个基础上往两边扩展。
    然后更新Maxright和pos。

3、统计答案

例题

Palindrome

using namespace std;
#include <iostream>
#include <cstring>
#include <algorithm>
char str[1000003];
char s[2000007];
int p[2000007];
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int T=1;
	for (cin>>str;str[0]!='E';++T,cin>>str)
	{
		int len=1;
		s[0]='#';
		for (char* ch=str;*ch;++ch)
		{
			s[len++]=*ch;
			s[len++]='#';
		}
		p[0]=1;
		int pos=0,Maxright=0,ans=0;
		for (int i=1;i<len;++i)
		{
			if (i<Maxright)
				p[i]=min(p[(pos<<1)-i],Maxright-i);
			else
				p[i]=1;
			int j,k;
			for (j=i-p[i],k=i+p[i];j>=0 && k<len && s[j]==s[k];--j,++k);
			p[i]=k-i;
			if (k-1>Maxright)
			{
				Maxright=k-1;
				pos=i;
			}
			ans=max(ans,p[i]-1);
		}
		cout<<"Case "<<T<<": "<<ans<<'\n';
	}
	return 0;
}
posted @ 2018-02-25 17:02  jz_597  阅读(121)  评论(0编辑  收藏  举报