马拉车的定义
马拉车本质是对中心扩展法(暴力算法)的优化。
马拉车是干什么的
Manacher算法帮助我们在给定的字符串中找到最长的回文子串。
为了简单起见,我们先只处理有奇数个字符的字符串,关于偶数个字符的字符串,在文章最后会给出解法。我们的处理思路和暴力算法基本一致,那就是从左到右一个字符一个字符来处理这个字符串,寻找以当前处理的字符为中心的最长回文串,假设字符串的长度是N,那我们就在寻找到的N个最长回文串中取最长的就是答案了。
符号说明
我们约定,c是我们处理当前字符时,已经找到的右边界最大的回文字符串的中心。l和r分别是这个最长的回文字符串的左界和右界,也就是最左边的字符索引和最右边的字符索引。现在,我们举个例子来理解c、l和r。
例子:“abacabacabb”
当从左到右一个字符一个字符计算时,我们用i表示当前正在处理的字符的索引,当i在索引1时,最长的回文字符串是 "aba"(长度=3)。
当i在索引5时,如下图所示:
最长的回文字符串的答案是9,c、l、r的值如图中所示。
不难看出,c所代表的最长回文字符串
现在我们知道了c、l和r表示什么,为了下面算法的讲解更加自然,我们需要了解一个概念:镜像索引。
对于以c为中心的任何一个回文字符串来说 索引j关于c的镜像是j',如下图所示:
观察上图,不难得出下面的计算公式:
c - j = j' - c
此时,j的镜像j':
j' = (2 * c) - j
模板
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 3e5 + 5;
char s[maxn], t[maxn];
int p[maxn];
int main() {
while (~scanf("%s", s)) {
int l = strlen(s), len = 0;
t[len++] = '$'; // 在字符串开头和结尾都添加一个特殊字符(如'$',
// 注意不要相同),使后续计算可以避免判断越界
t[len++] = '#';
for (int i = 0; i < l; ++i) {
t[len++] = s[i];
t[len++] = '#';
}
t[len] = '&';
int center = 0, max_right = 0;
for (int i = 1; i < len; ++i) {
int i_mirror = 2 * center - i;
if (max_right >
i) { // 在最右边界的覆盖范围内, 就利用回文串特征计算长度
p[i] = min(max_right - i,
p[i_mirror]); // 使用min()是为了防止超出最右边界
} else {
p[i] = 0;
}
while (t[i - 1 - p[i]] == t[i + 1 + p[i]])
++p[i];
if (i + p[i] > max_right) { // 更新右边界的回文串中心
center = i;
max_right = i + p[i];
}
}
int max_len = 0;
// int pos = 0; //记录最长回文子串中心的位置
for (int i = 1; i < len; ++i)
if (max_len < p[i]) {
max_len = p[i];
// pos = i;
}
printf("%d\n", max_len); //最长回文串的起始位置为: (pos - max_len) / 2
}
return 0;
}
标签:int,manacher,len,++,详解,C++,max,字符串,回文
From: https://www.cnblogs.com/ypzmlmf/p/manacher.html