简介
朴素的算回文串的办法一般是O(n ^ 2) 或 O(n ^ 3)的。而Manacher发明的马拉车算法能将空间复杂度和时间复杂度均优化到O(n)的线性。
具体算法过程是:
1、将字符串中加入#
如 abcde -> ##a#b#c#d#e
举个例子 一个字符串s = abbahopxpo,转换为$#a#b#b#a#h#o#p#x#p#o#(这里的字符 $ 只是为了防止越界,下面代码会有说明),如此,s 里起初有一个偶回文abba和一个奇回文opxpo,被转换为#a#b#b#a#和#o#p#x#p#o#,长度都转换成了奇数。
定义一个辅助数组p,其中p[i]表示以 i 为中心的最长回文的半径。
这样的话p[i] - 1正好是原字符串中最长回文串的长度
然后只要求出p数据就好了。
评测见洛谷:P3805
模板
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>
#include <queue>
using namespace std;
static const int MAXN = 31000015;
char s[MAXN];
char new_s[MAXN];
int p[MAXN];
int Init();
int Manacher();
int main() {
scanf("%s",s);
printf("%d\n",Manacher());
return 0;
}
int Manacher() { //马拉车算法主题
int len = Init(); //初始化并返回长度
int max_len = -1;
int id = 0,mx = 0;
for(int i = 1;i < len;++i) {
if(i < mx) p[i] = min(p[2 * id - i],mx - i); // 2 * id - i指i关于id的对称点j
else p[i] = 1;
while(new_s[i - p[i]] == new_s[i + p[i]]) p[i]++;
if(mx < i + p[i]) {
id = i;
mx = i + p[i];
}
max_len = max(max_len,p[i] - 1);
}
return max_len;
}
int Init() { //初始化并返回new_s长度
int len = strlen(s);
new_s[0] = '$';
new_s[1] = '#';
int j = 2;
for(int i = 0; i < len;++i) {
new_s[j++] = s[i];
new_s[j++] = '#';
}
new_s[j] = '\0';
return j;
}
参考地址:https://segmentfault.com/a/1190000008484167
文章评论