马拉车算法是一个用于求字符串中最长回文子串的算法,通常若我们暴力枚举计算最长回文子串时间复杂度为o(n^2),而马拉车算法的时间复杂度是o(n)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int n,ans; 6 int hw[22000005]; 7 char s[22000005]; 8 char a[11000005]; 9 void change()//把偶数或奇数的字符串都转化为奇数字符串,便于枚举轴操作 10 { 11 s[0] = s[1] = '#'; 12 for(int i = 0;i < n;i ++) 13 { 14 s[i * 2 + 2] = a[i]; 15 s[i * 2 + 3] = '#'; 16 } 17 n = n * 2 + 2; 18 s[n] = 0; 19 } 20 void manacher() 21 { 22 int mr = 0,mid; 23 for(int i = 1;i <= n;i ++) 24 { 25 if(i < mr)//当一个点在对称回文串的右端点内,由于轴是由每个枚举的位置转移的,所以每个枚举的位置一定在轴的右端 26 { 27 hw[i] = min(hw[(mid * 2) - i],mr - i);//以i为轴的最长回文串的半径可以由,与i对称的j(j = mid * 2 - i)转移,但是如果以j为轴的对称回文子串的半径超过了以mid为轴的对称回文子串的半径,由于mr外的情况我们还没有判断,而且如果这时i能由j扩展的话,那么mr会扩大,与事实不符,所以这时hw[i]=i到mr的距离(卡在mr上),如果有能扩展的情况,暴力枚举 28 } 29 else hw[i] = 1;//如果我们枚举的位置在mr外,只能暴力枚举 30 while(s[i + hw[i]] == s[i - hw[i]])hw[i] ++;//暴力枚举扩展hw[i] 31 if(hw[i] + i > mr)//若一个位置扩展出的回文串的右端点超出了目前的对称回文串的右端点,或目前枚举的位置超过了对称的右端点,这个对称轴对后面没有用了,更新对称回文串的右端点以及对称回文串的轴 32 { 33 mr = hw[i] + i; 34 mid = i; 35 } 36 } 37 } 38 int main() 39 { 40 scanf("%s",a); 41 n = strlen(a); 42 change(); 43 manacher(); 44 for(int i = 0;i < n;i ++) 45 { 46 ans = max(ans,hw[i]); 47 } 48 printf("%d",ans - 1); 49 return 0; 50 }