51 nod 1089 最长回文子串 V2(Manacher算法)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Rem_little_fan_boy/article/details/82940910

题目传送门

1089 最长回文子串 V2(Manacher算法) 

基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题

 收藏

 关注

回文串是指aba、abba、cccbccc、aaaa这种左右对称的字符串。

输入一个字符串Str,输出Str里最长回文子串的长度。

Input

输入Str(Str的长度 <= 100000)

Output

输出最长回文子串的长度L。

Input示例

daabaac

Output示例

5

传说中的“马拉车算法”。

大体思路:这道题目的做法首先必须要对字符串进行填充,从而避免掉奇回文和偶回文的繁琐。比如我们如果要对字符串‘abba’进行填充就需要将它填充成为‘@#a#b#b#a#\0\0......’,填充过后我们会发现最长回文字符串的长度就等于这个字符串中以某个字符为中心向两侧延伸到的最大回文字符串的长度再减去1,比如本例中就是:lenth(#b#a#)-1=4。

具体代码思路:大神传送门

#include <iostream>
#include <cstring>
#define maxn 100002
using namespace std;
char str[maxn],str_new[maxn*2+5];
int str_len[maxn*2+5];
int init(int n)                      //对字符串进行填充得到一个新的字符串。 
{
	str_new[0]='@';
	int t=1;
	for(int i=0; i<n; ++i)
	{
		str_new[t++]='#';
		str_new[t++]=str[i];
	}
	str_new[t++]='#';
	str_new[t]='\0';
	return t;
}                                         
int  Manacher(int n)
{
	int m=init(n);
	int Max=0,P=1,mx=0,i;           //mx是目前所有回文字符串中能达到的最右侧的边界值,Max用来记录最大字符串长度,P则用来记录能达到最右侧 回文字符串的中心值 
	for(i=1; i<m; ++i)
	{
		if(i<mx)                                 //i点未达到mx时 
		str_len[i]=min(str_len[2*P-i],mx-i);    //新的点的回文字符串以i为中心,其长度我们可以从其与P的对称点j的长度开始计算,节省时间 
		else                                    //超过mx时就只有老老实实去计算了,因为没有对称点了 
		str_len[i]=1;
		while(str_new[i+str_len[i]]==str_new[i-str_len[i]])
		{
			str_len[i]++;
		}
		if(mx<i+str_len[i])                  //这个if可以去掉,但我们的目的是寻找最大的mx值,进而可以更有机会执行 if (i < mx)这句代码,从而提高效率
		{
			mx=i+str_len[i];
			P=i;
		}
	    if(Max<str_len[i]-1)
	    Max=str_len[i]-1;
	}
	return Max;
}
int main()
{
	cin>>str;
	int n=strlen(str);
	cout<<Manacher(n)<<endl;
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/Rem_little_fan_boy/article/details/82940910