字符串最大回文子串(Manacher 算法)

以HDU-3068为例

题目:
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.回文就是正反读都是一样的字符串,如aba, abba等

Input:
输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S两组case之间由空行隔开(该空行不用处理)字符串长度len <= 110000

Output:
每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.

Sample Input
aaaa

abab

Sample Output
4
3

#include<cstdio>
#include<cstring>
#include <algorithm>
#include<cmath>
using namespace std;

const int maxn = 1e5+1e4+10;
char c[maxn];//原字符串
char s[maxn*2];//转换后的字符串
int p[maxn*2];//P可以理解为回文字符串的半径

void init(){
	int l=strlen(c);
	int i;
	for(i=0; i<l; ++i){
		s[i*2+1]='#';
		s[i*2+2]=c[i];
	}
	s[0]='@';//字符串开头增加一个特殊字符,防止越界
	s[i*2+1]='#';
	s[i*2+2]='0';//字符串结尾加一个字符,防止越界
}
int Manacher(){
	int mx=0,id=0;//mx即为当前计算回文串最右边字符的最大值
	int i;
	for(i=1; s[i]!='0'; ++i){
		if(mx>i)
        	p[i]=min(p[2*id-i],mx-i);
        else
        	p[i]=1;
		while(s[i+p[i]] == s[i-p[i]])
			p[i]++;
		if(i+p[i]>mx){
			mx=i+p[i];
			id=i;
		}
	}
	mx=0;
	for(int i=0; s[i]!='0'; ++i){
		if(p[i]>mx)
			mx=p[i];
	}
	return mx-1;//返回p[i]中的最大值-1即为原串的最长回文子串额长度 
}
int main(){
	while(~scanf("%s",c)){
		init();
		printf("%d\n",Manacher());
	}
	return 0;
}

O(n)算法
在每个字符中间插入'#'号,使原来偶数长的回文串的中心轴可以用'#' 表示出来。

三个链接以供参考
https://blog.csdn.net/synapse7/article/details/18908413

https://mp.weixin.qq.com/s?__biz=MzIzMTE1ODkyNQ==&mid=2649410225&idx=1&sn=ed045e8edc3c49a436a328e5f0f37a55&chksm=f0b60f53c7c18645b4c04a69ad314723cce94ed56994d6f963c2275a2db8d85f973f15f508e4&mpshare=1&scene=23&srcid=1001JCsBlpxgUWjgixasChNQ#rd

https://blog.csdn.net/csdn_kou/article/details/82917937

posted @ 2020-05-16 18:28  wansheking  阅读(428)  评论(0)    收藏  举报