求最大回文子串(manacher算法)

原文出处:http://www.cnblogs.com/grandyang/p/4475985.html

manache算法俗称马拉车算法,该算法的作用是求一个字符串中的最大回文子串,例如"11123321"。

马拉车算法找回文串的方法是从中间往左右两边找,但是这样找就会遇到几个问题;第一个,比如"1221",马拉车算法就不好找(所以会用到预处理);第二个这样暴力找的时间开销大,所以会用一个p数组来记录一下包括了当前能够形成回文串的最大回文半径(回文串字符数量的一半,这里的一半肯定整数,不会出现小数,原因请看预处理),来快速跳转找当前回文串的一个可能大小(因为后面可能会增大,但一定不会减小),举个栗子,如下图:

因为一个以id为中心的回文串中的两边个对称的回文串(一个以2*id-1为中心的回文串,另一个以i为中心的回文串是相等的)所以:

当2*mx-i<=p[2*id-i]时,

1

当2*mx-i>p[2*id-i]时,2

  1. 预处理

将输入的字符在每一个字符的两边加上一个"#"(其他符号也行,必须与输入的字符不一样),在一个字符前面加个"*"(其他符号也行,不能和输入字符或者"#"一样),例如:

"11123321"     ->    "*#1#1#1#2#3#3#2#1#"

加"#"的原因:可以将每一个原字符子串变成一个奇数个数的子串,保证每个子串是一字符为中心的串,如果不是以一个字符为中心的串,在求一个回文串时只能去一个字符一个字符扩展后再去判断。

加"*":提供非回文(结束回文扩展操作,防止溢出,出现s[-1]的情况)。

 

题目地址:https://ac.nowcoder.com/acm/contest/549/B

code:

/*
	马拉车算法manacher 
*/

#include<bits/stdc++.h>

using namespace std;

const int mn=10005;

int p[mn*2],id,mx;
string s;

void manache(string t){
	int i,j;
	s.clear();
	s+="*#";
	for(i=0;i<2*t.size();i++){
		s+=t[i%t.size()];
		s+="#";
	}
//	cout<<s<<endl;
	int maxl=0;
	memset(p,0,sizeof p);
	for(i=0;i<s.size();++i){
		p[i]=mx>i?min(p[2*id-i],mx-i):1;
		while(s[i-p[i]]==s[i+p[i]]&&(p[i]-1<s.size()/4)) ++p[i];
		if(mx<p[i]+i){
			mx=i+p[i];
			id=i;
		}
//		cout<<p[i]<<' '<<i<<endl;
		maxl=max(maxl,p[i]);
	}
	cout<<maxl-1<<endl;
}

int main(){
	string t;
	while(cin>>t){
		manache(t);
	}
	
	return 0;
}

如果还是看不懂的话,请看原文博客,图片画的灰常具体!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值