manacher马拉车算法

manacher算法

用于快速求解字符串中的最长回文子串
数组 p: p[i]表示以字符t[i]为半径的回文子串长度
规律:

  • 最大半径减 1 等于最长回文串的长度
  • 最长回文字符的起始位置是中间位置减去半径在除以 2

对于模板
首先预处理数组s得到数组t
再从1到n遍历更新 $p[i]=mx>i ? min(mx-i,p[(id<<1)-i]) : 1 $
再对于每个p[i]暴力扩展两边实现最大
之后统计mx,id,maxl,maxp
最终输出最长回文子串

模板

manacher 带注释

string manacher(string s)
{
	//预处理s,方便计算p数组,此处仅前+'$',中和后+'#'
	string t="$#";
	for(auto a:s){
		t+=a;
		t+='#';
	}
	//下面开始p数组的求解
	//mx和id为所有已经求得的回文串的右端点的最大值和中心点,初始默认为0
	//maxl与maxp统计最大的回文子串的长度和开始位置
	vector<int> p(t.size()+5,0);
	int mx=0,id=0,maxl=0,maxp=0;
	for(int i=1;i<t.size();++i){
		//利用已经维护的数组p[1~i-1]的值先一步更新p[i]的大小
		p[i]=mx>i ? min(mx-i,p[(id<<1)-i]) : 1 ;
		//中心扩展法更新最大值
		while(t[i+p[i]]==t[i-p[i]]) ++p[i];
		//更新mx与id
		if(i+p[i]>mx){
			mx=i+p[i];
			id=i;
		}
		//更新最大回文子串
		if(p[i]>maxl){
			maxl=p[i];
			maxp=(i-p[i])/2;
		}
	}
	return s.substr(maxp,maxl-1);
}

manacher 无注释

string manacher(string s)
{
	string t="$#";
	for(auto a:s){
		t+=a;
		t+='#';
	}
	vector<int> p(t.size()+5,0);
	int mx=0,id=0,maxl=0,maxp=0;
	for(int i=1;i<t.size();++i){
		p[i]=mx>i ? min(mx-i,p[(id<<1)-i]) : 1 ;
		while(t[i+p[i]]==t[i-p[i]]) ++p[i];
		if(i+p[i]>mx){
			mx=i+p[i];
			id=i;
		}
		if(p[i]>maxl){
			maxl=p[i];
			maxp=(i-p[i])/2;
		}
	}
	return s.substr(maxp,maxl-1);
}

例题

板子题

hdu 3068
洛谷 P3805
ABC 320 B - Longest Palindrome

相关资料

  1. 马拉车算法(不懂问我)
posted on 2023-07-01 14:41  Qiansui  阅读(13)  评论(0编辑  收藏  举报