manacher算法详解

来源:互联网 发布:利雅得机场数据 编辑:程序博客网 时间:2024/06/01 07:39

今天同学问我求字符串中最大回文串的问题,最先想到的就是暴力了,时间复杂度为O(n*n),而且还要考虑回文串长

为奇偶两种情况。后来同学说网上有O(n)的解法,就搜了下,果然manacher是在O(n)的时间复杂度里解决的。但是

面那个求数组p的过程还是不怎么理解,特在此发表希望得到论坛朋友们的指教。下面是实现代码:

#include<iostream>#include<cstring>using namespace std;int manacher (char* s, int len){int nlen = 2 * len + 3;char* str = new char[nlen];int i = 0;int max = 0;str[0] = '$';str[1] = '#';for (; i < len; i++){str[i * 2 + 2] = s[i];str[i * 2 + 3] = '#';}str[nlen - 1] = 0;int* p = new int[nlen];for (int i = 1; i < nlen; i++){p[i] = 0;}int id = 0;for (i = 1; i < nlen; i++){if (max > i)p[i] = min(p[2*id-i], p[id]+id-i);elsep[i] = 1;while (str[i+p[i]] == str[i-p[i]])p[i]++;if (p[i]+i > max){max = p[i] + i;id = i;}}int mx = 0;for (i = 1; i < nlen; i++){if (mx < p[i] - 1)mx = p[i] - 1;}return mx;}int main(){char ch[100];while (cin >> ch){cout << manacher(ch, strlen(ch)) << endl;}return 0;}



补:后来又网上找了好久,终于找到一个写的比较符合我的习惯的了。看完终于理解了这个算法。这个算法的核心就

是P的求解了,也就是

if (max > i)    p[i] = min(p[2*id-i], p[id]+id-i);else    p[i] = 1;
这里max表示的是扫面str[i]后,匹配到的最远的位置。而id则记录取这个max的i值。

if (max > i)    p[i] = min(p[2*id-i], p[id]+id-i);
这个代码就是为了避免很多没必要的重复匹配。这个就利用了回文串的对称性。


i点关于id点的对称点j = 2*id - i。根据对称性,p[j]的回文串也是可以对称到i这边的,但是如果p[j]的回文串对称过来以

后超过max的话,超出部分就不能对称过来,因为超出的部分是我们还没有匹配的。所以我们这里p[i]的值应该取两者

中的较小者:p[i] = min(p[2*id-i], max-i)。然后通过while (str[i+p[i]] == str[i-p[i]])  p[i]++;继续匹配后面的。




原创粉丝点击