经典算法——最长回文子串

时间限制:
1000ms 单点时限:
1000ms 内存限制:
64MB

描述

   小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进。

   这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?”

   小Ho奇怪的问道:“什么叫做最长回文子串呢?”

   小Hi回答道:“一个字符串中连续的一段就是这个字符串的子串,而回文串指的是12421这种从前往后读和从后往前读一模一样的字符串,所以最长回文子串的意思就是这个字符串中最长的身为回文串的子串啦~”

   小Ho道:“原来如此!那么我该怎么得到这些字符串呢?我又应该怎么告诉你我所计算出的最长回文子串呢?

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

提示一
 
提示二
 
提示三
 
提示四 样例输入

3
abababa
aaaabaa
acacdas

样例输出

7
5
3

《经典算法——最长回文子串》

《经典算法——最长回文子串》

《经典算法——最长回文子串》

#include<iostream>
#include<cstdio>  
#include<string> //cin>>输入字符串必须添加的头文件
#include<cstring>//C++中使用memset必须添加的头文件
#include<algorithm>  
#include<vector>
using namespace std;

const int N = 2 * (1e6) + 3;
char s[N];
int p[N];

//利用manacher算法求最长回文子串
void manacher(char* s, int len)
{
	p[0] = 1;
	int mx = 0, id = 0;
	for (int i = 1; i < len; i++) 
	{
		p[i] = mx > i ? min(p[id * 2 - i], mx - i) : 1;
		while (s[i + p[i]] == s[i - p[i]])  p[i]++;
		if (i + p[i] > id + p[id]) 
		{
			id = i;
			mx = i + p[i];
		}
	}
}

int main()
{
	int n;
	vector<string>vec;
	while (cin >> n)
	{
		vec.clear();
		for (int k = 0; k < n; ++k){
			cin >> s;
			vec.push_back(s);
		}
		for (int k = 0; k < n; ++k){
			memset(s, 0, sizeof(s));//每次求得一个字符串的最长回文子串后,必须将数组s和p清零,不然会对后面的结果产生影响
			memset(p, 0, sizeof(p));
			int len = vec[k].size();
			for (int j = 0; j < len; ++j){
				s[j] = vec[k][j];
			}
			for (int i = len; i >= 0; i--) 
			{
				s[(i << 1) + 1] = '#';
				s[(i << 1) + 2] = s[i];
			}
			s[0] = '*'; //防止数组越界  
			len = len * 2 + 2;
			manacher(s, len);
			int ans = 0;
			for (int i = 0; i < len; i++)
				ans = max(ans, p[i] - 1);
			printf("%d\n", ans);
		}
		return 0;
	}
}

    原文作者:zhihua_bupt
    原文地址: https://blog.csdn.net/geekmanong/article/details/51036984
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞