回文子串的最大长度

回文子串的最大长度

如果一个字符串正着读和倒着读是一样的,则称它是回文的。
给定一个长度为N的字符串S,求他的最长回文子串的长度是多少。

输入格式
输入将包含最多30个测试用例,每个测试用例占一行,以最多1000000个小写字符的形式给出。

输入以一个以字符串“END”(不包括引号)开头的行表示输入终止。

输出格式
对于输入中的每个测试用例,输出测试用例编号和最大回文子串的长度(参考样例格式)。
每个输出占一行。

输入样例:

abcbabcbabcba
abacacbaaaab
END

输出样例:

Case 1: 13
Case 2: 6

思路:
先分别从头至尾,从尾到头哈希一次
枚举回文串中心和长度,将回文串分成前后两半,再判断两半是否构成回文

倒着的哈希:
对于一个长度为l的字符串a(下标从1开始)
Hash[a] = a[1]*pl-1 + a[2]*pl-2 + … + a[l]*p0


TLE
一个个加长度的…

#include <iostream>
#include <cstdio>
using namespace std;
#define N 1000005
unsigned long long P=131;
unsigned long long Hash1[N],Hash2[N],p[N];
unsigned long long cal1(int l,int r)
{
	return Hash1[r]-Hash1[l-1]*p[r-l+1];
}
unsigned long long cal2(int l,int r)
{
	return Hash2[l]-Hash2[r+1]*p[r-l+1];
}
int main(){
	p[0]=1;
	for(int i=1;i<=1000000;++i)
	{
		p[i]=p[i-1]*P;
	}
	string s;
	int t=0,ans;
	while(cin>>s && s!="END")
	{
		int m=s.size();
		Hash1[0]=0;
		ans=1;
		for(int i=1;i<=m;++i)
		{
			Hash1[i]=P*Hash1[i-1]+(s[i-1]-'a'+1);
		}
		Hash2[m+1]=0;
		for(int i=m;i>0;--i)
		{
			Hash2[i]=P*Hash2[i+1]+(s[i-1]-'a'+1);
		}
		for(int i=1;i<=m;++i)//枚举以s[i]为中心的 长度为奇数的回文串
		{
			int p=1;//向左右拓展的长度 
			while(1)
			{
				if(cal1(i-p,i)==cal2(i,i+p) && i-p>0 && i+p<=m)
					p++;
				else
					break;
			}
			p--;
			ans=max(ans,2*p+1);
		}
		for(int i=1;i<m;++i)//枚举以s[i]和s[i+1]之间的缝隙为中心的 长度为偶数的回文串 
		{
			int p=1;
			while(1)
			{
				if(cal1(i-p+1,i)==cal2(i+1,i+p) && i-p+1>0 && i+p<=m)
					p++;
				else
					break;
			}
			p--;
			ans=max(ans,2*p);
		}
		t++;
		printf("Case %d: %d\n",t,ans);
	}
	return 0;
}

AC
二分枚举长度,很多细节要注意(WA了N次…)

#include <iostream>
#include <cstdio>
using namespace std;
#define N 1000005
unsigned long long P=131;
unsigned long long Hash1[N],Hash2[N],p[N];
unsigned long long cal1(int l,int r)
{
	return Hash1[r]-Hash1[l-1]*p[r-l+1];
}
unsigned long long cal2(int l,int r)
{
	return Hash2[l]-Hash2[r+1]*p[r-l+1];
}
int main(){
	p[0]=1;
	for(int i=1;i<=1000000;++i)
	{
		p[i]=p[i-1]*P;
	}
	string s;
	int t=0,ans;
	while(cin>>s && s!="END")
	{
		int m=s.size();
		Hash1[0]=0;
		ans=1;
		for(int i=1;i<=m;++i)
		{
			Hash1[i]=P*Hash1[i-1]+(s[i-1]-'a'+1);
		}
		Hash2[m+1]=0;
		for(int i=m;i>0;--i)
		{
			Hash2[i]=P*Hash2[i+1]+(s[i-1]-'a'+1);
		}
		for(int i=2;i<m;++i)//枚举以s[i-1]为中心的 长度为奇数的回文串
		{
			int l=0,r=min(i-1,m-i),p;//向左右拓展的长度 
			while(l<r)
			{
				p=(l+r+1)>>1;
				if(i-p>0 && i+p<=m && cal1(i-p,i-1)==cal2(i+1,i+p))
					/*printf("#1 %d %d %d %d\n",i,p,i-p,i+p),*/l=p;
				else
					r=p-1;
				//printf("%d %d %d\n",l,r,p);
				//printf("%d %d %d %d\n",i,p,i-p,i+p);
			}
			//printf("#1 %d %d %d %d\n",i,l,r,p);
			if(!(i-p>0 && i+p<=m && cal1(i-p,i-1)==cal2(i+1,i+p)))//可能一次循环中p不满足条件但l>=r跳出了 
				p--;
			ans=max(ans,p<<1 | 1);
		}
		for(int i=1;i<m;++i)//枚举以s[i-1]和s[i]之间的缝隙为中心的 长度为偶数的回文串 
		{
			int l=0,r=min(i,m-i),p;
			while(l<r)
			{
				p=(l+r+1)>>1;
				//printf("#2 %d %d %d %d\n",i,l,r,p);
				if(i-p+1>0 && i+p<=m && cal1(i-p+1,i)==cal2(i+1,i+p))
					/*printf("#2 %d %d %d %d\n",i,p,i-p+1,i+p),*/l=p;
				else
					r=p-1;
				//printf("%d %d %d %d\n",i,p,i-p+1,i+p);
			}
			//printf("#2 %d %d %d %d\n",i,l,r,p);
			if(!(i-p+1>0 && i+p<=m && cal1(i-p+1,i)==cal2(i+1,i+p)))
				p--;
			ans=max(ans,l<<1);
		}
		t++;
		printf("Case %d: %d\n",t,ans);
	}
	return 0;
}

你可能感兴趣的:(回文子串的最大长度)