Hiho-最长回文

先从标准输入读取一个整数N(N<=30),代表我给你的字符串的个数,然后接下来的就是我要给你的那N个字符串(字符串长度<=10^6)啦。而你要告诉我你的答案的话,只要将你计算出的最长回文子串的长度按照我给你的顺序依次输出到标准输出就可以了!你看这就是一个例子。”

提示一  提示二  提示三  提示四
样例输入
3
abababa
aaaabaa
acacdas
样例输出
7
5
3


#include<iostream>
#include<string>
using namespace std;
int getMaxSym(string str)
{
	int maxlength = 0;
	int len = str.length();
	int ptag = 0;
	while(ptag < len)
	{
		int left = ptag - 1;
		int right = ptag + 1;
		int oddlenght = 1;
		while(left >= 0 && right < len && str[left] == str[right])
		{
			left--;
			right++;
			oddlenght += 2;
		}
		if(oddlenght > maxlength)
		{
			maxlength = oddlenght;
		}
		//偶数子字符串
		left = ptag;
		right = ptag + 1;
		int evenlength = 0;
		while(left >= 0 && right < len && str[left] == str[right])
		{
			left--;
			right++;
			evenlength += 2;
		}
		if(evenlength > maxlength)
		{
			maxlength = evenlength;
		}

		ptag++;
	}
	return maxlength;
}
int main()
{
	int k = 0;
	cin>>k;
	if(k == 0)
	{
		return 0;
	}
	for(int i = 0; i < k; i++)
	{
		string src;
		cin>>src;
		cout<<getMaxSym(src);
	}
	return 0;
}
上面的方法就是利用遍历中心点,然后向两边进行扩展,然后进行匹配的方法,但是这种方法还是很费时间

在算法中有一种称为Manacher的算法,很好的利用了之前计算出来的最长回文的结果进行判断:

#include<iostream>
#include<string>
#include<cstring>
using namespace std;

char * pre(const char *str)
{
	int length = strlen(str);
	char *prestr = new char[2*length + 4];
	prestr[1] = '$';
	for(int i=0;i<length;i++)
	{
		prestr[2*(i+1)] = '#';
		prestr[2*(i+1)+1] = str[i];
	}
	prestr[2*length+2]='#';
	prestr[2*length+3]='\0';
	return prestr;
}
int getMaxSym(const char *str)
{
    if(NULL == str)
    {
        return 0;
    }
	char *prestr = pre(str);
	int mx =0, pi=1;//边界和对称中心
	int len = strlen(prestr);
	//辅助数组
	int *p = new int[len];
	p[0] = 0;
	for(int i=1;i<len;i++)
	{
		if(mx>i)
		{
			p[i]=min(mx-i,p[2*pi-i]);//核心
		}
		else
		{
			p[i]=1;
		}
		while(prestr[i-p[i]]==prestr[i+p[i]]&&i-p[i]>0&&i+p[i]<len)
		{
			p[i]++;
		}
		if(i+p[i] > mx)
		{
			mx = p[i] + i;
			pi = i;
		}
	}
	//最大回文字符串长度
	int maxlen = 0;
	for(int i=0;i<len;i++)
	{
		if(p[i]>maxlen)
		{
			maxlen = p[i];
		}
	}
	delete []prestr;
	delete []p;
	return maxlen - 1;
}
int main()
{
	int k = 0;
	cin>>k;
	if(k == 0)
	{
		return 0;
	}
	for(int i = 0; i < k; i++)
	{
		string src;
		cin>>src;
		int result = getMaxSym(src.c_str());
		cout<<result<<endl;
	}
	return 0;
}

相关的解释有:

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

之所以在原始字符串中加入一些特殊字符串是因为我们希望处理出来的回文我们希望都是奇数的

在上面的代码中

mx 表示之前处理的最长回文的最右端标记, p[i] 表示之前获得的最长回文的最长半径






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值