学习Manacher算法需要建立三个概念。
三个概念:
回文半径数组
回文右边界
右边界的最早中心位置
算法流程:
若 i 不在右边界内部:
可能性:暴力向两边扩展
若 i 在右边界内部:
可能性1:如若i对应的i’的半径包括在大的回文半径,i的回文半径等于i‘的回文半径。
t 【F [a b a] k t k [a b a] F】s
可能性2:如若i对应的i’的半径超过了大的回文半径,i的回文半径还等于i’的回文半径。
[a b【C E C b a] t t t a b [C E C】F
可能性3:如若i对应的i’的半径正好卡在大的回文半径,那么以i‘的半径长度为基础继续向两边拓展。
S【 [a b c E c b a] F F F a b c E c b a】F
代码演示
#include <stdio.h>
#include <string.h>
#include <algorithm>
using std::min;
using std::max;
int Manacher(char *str) {
int len = strlen(str + 1);
char now[256] = {0};
for (int i = 1; i <= len; ++i) now[2 * i - 1] = '$', now[2 * i] = str[i];
now[0] = '#';
now[len = len * 2 + 1] = '$';
int mx = -1;
int id = -1;
int ans = -1;
int arr[256] = {0};
for (int i = 1; i <= len; ++i) {
arr[i] = (i < mx ? min(mx - i, arr[2 * id - 1]) : 1);
while (now[i + arr[i]] == now[i - arr[i]]) arr[i]++;
if (i + arr[i] > mx) {
mx = i + arr[i];
id = i;
}
ans = max(ans, arr[i]);
}
return ans - 1;
}
int main() {
char str[128] = {0};
while (~scanf("%s", str + 1)) {
int ans = Manacher(str);
printf("%d\n", ans);
}
return 0;
}