最长回文子串-Manacher算法
给你一个字符串,要求出它的最长回文子串的长度。
Manacher算法
第一步:在字符串所有的空隙中插入一个不会在原串中出现的字符
aba ———> #a#b#a#
abba ———> #a#b#b#a#
这样永远不会连续相同的字符,所以会使得所有的串都是奇数长度的。
第二步:定义一个数组RL,RL[i]表示以i为对称点的回文串的半径长度。
引入两个辅助变量MaxRight以及pos,MaxRight表示当前判断过的所有回文串所能到达的最右侧的下标,pos表示当前最长回文子串的对称中心下标。
如图
然后我们可以从左至右的遍历字符串来求RL[ i ],那么i必定在pos的右侧,因为pos表示i之前的最长回文子串的对称轴的下标。但是此时i在MaxRight的左边还是右边任然是不确定的。
1)i在MaxRight的左侧
此时我们可以找到i关于pos对称的点j,并且以i和以j为对称轴的回文串有一部分也是相同的。
1.以j为对称轴的回文串的半径比MaxRight到i的距离小,如下图
这时以i为对称轴的回文串可能更长,那我们可以接着对以i为对称轴,以RL[j]为半径开始扩张进行回文串的判断直到到达边界。
2.以j为对称轴的回文串的半径比MaxRight到i的距离大
这个时候我们只能确定i到MaxRight的这个部分是回文串,并无法确定MaxRight右侧的情况,那么我们就直接以i为对称轴,以MaxRight-i开始向左右两侧扩张判断回文。
同时我们也要不断的更新MaxRight以及pos的值,应为有可能得到更大的MaxRight
2)当i在MaxRight的右边时
这个时候无法找i关于pos的对称点,所以此时只能从i开始对左右两边进行判断回文了。
代码实现如下:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<vector> 7 #include<set> 8 #include<map> 9 #include<iomanip> 10 using namespace std; 11 #define inf 1<<29; 12 13 string s; 14 char s_new[2000]; 15 int p[2000]; //p[i]表示以 i 为中心的最长回文的半径 16 17 int Init() 18 { 19 int len = s.size(); 20 s_new[0] = '$'; 21 s_new[1] = '#'; 22 int j = 2; 23 24 for (int i = 0; i < len; i++) 25 { 26 s_new[j++] = s[i]; 27 s_new[j++] = '#'; 28 } 29 30 s_new[j] = '\0'; // 别忘了哦 31 32 return j; // 返回 s_new 的长度 33 } 34 35 int Manacher() 36 { 37 int len = Init(); // 取得新字符串长度并完成向 s_new 的转换 38 int max_len = -1; // 最长回文长度 39 40 int id; 41 int mx = 0; //mx 代表以 id 为中心的最长回文的右边界 42 43 for (int i = 1; i < len; i++) 44 { 45 if (i < mx) 46 p[i] = min(p[2 * id - i], mx - i); // 需搞清楚上面那张图含义, mx 和 2*id-i 的含义 2*id-i表示i关于id的对称点(i在id右侧) 47 else 48 p[i] = 1; 49 50 while (s_new[i - p[i]] == s_new[i + p[i]]) // 不需边界判断,因为左有'$',右有'\0' 51 p[i]++; 52 53 // 我们每走一步 i,都要和 mx 比较,我们希望 mx 尽可能的远,这样才能更有机会执行 if (i < mx)这句代码,从而提高效率 54 if (mx < i + p[i]) 55 { 56 id = i; 57 mx = i + p[i]; 58 } 59 60 max_len = max(max_len, p[i] - 1); 61 } 62 63 return max_len; 64 } 65 66 int main() 67 { 68 while (printf("请输入字符串:\n")) 69 { 70 getline(cin,s); 71 printf("最长回文长度为 %d\n\n", Manacher()); 72 } 73 // cout.setf(ios::fixed); 74 // cout<<setprecision(4)<<16.0; 75 return 0; 76 }
原文链接: