最长回文字串 Manacher算法 时间复杂度O(N)

最长回文字串 Manacher算法 时间复杂度O(N)_第1张图片



这个图很经典解释也很清楚了,但是我开始看也看不懂。。实在太菜了。
解释一下重点部分:
if(p[id]+id>i) p[i]=min(p[2*id-i],p[id]+id-i);  
p[id]是以id为中心点的回文串的半径,当i在其范围内时,i的半径取值需要考虑其是否完全包含在id内,如果包含就直接取值;不包含的话,不包含的部分还未匹配因此只能取已知的。


j是i关于id点的对称点(j=2*id-i)当 p[id]+id-i > P[j] 的时候,以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,由于 i 和 j 对称,以S[i]为中心/的回文子串必然包含在以S[id]为中心的回文子串中,所以必有 P[i] = P[j]。
当 P[j] > mx - i 的时候,以S[j]为中心的回文子串不完全包含于以S[id]为中心的回文子串中,但是基于对称性可知,也就是说以S[i]为中心的回文子串,其向右至少会扩张到mx的位置,也就是说 P[i] >= mx - i。至于mx之后的部分是否对称,就只能老老实实去匹配了。
else p[i]=1;    i不在id范围内,长度暂时定为只有自身为1

#include 
using namespace std;
const int AX = 2e6+666;
char s[AX];
int p[AX];
int main(){
	int T;
	cin>>T;
	while(T--){
		int ans = 0;
		memset(p,0,sizeof(p));
		scanf("%s",s);
		int size = strlen(s);
		for(int i=size;i>=0;i--){
			s[2*i+2] = s[i];
			s[2*i+1] = '#';
		}	
		s[0] = '$';
		int id = 0;
		int mx = 0;
		for(int i=2;i<2*size+1;i++){
			if(p[id]+id > i) p[i] = min(p[id]+id-i,p[2*id-i]);
			else p[i] = 1;
			while(s[i-p[i]] == s[i+p[i]]) ++p[i];
			if(mx < i+p[i]){
				id = i;
				mx = p[i]+i;
			}
			ans = max(p[i],ans);
		}
		cout<

 
   


你可能感兴趣的:(暑期集训刷题算法复习(新手,))