一、概念介绍
1.回文半径,例 aabxbcc,xbcc为回文半径
2.回文直径 ,例 aabxbcc,aabxbcc为回文直径
3.最右回文边界,记录最右回文边界的位置。R
4.取得最右回文边界的中心C。
二、Manecher算法
这里先对字符串处理下,每个字符中间填充个字符’#’
分情况讨论,i表示每个字符串index
1.i 在 R外 如:abcbad
i的回文半径只能暴力往外扩
R' C R
d b a b x b a c x
i
2.i 在 R内: i’ 表示 i 基于 C 的对称点,R‘ 表示 R基于C的对称点
1). i’ 的最左回文边界在 R‘ 内 :
i'的回文半径是2,可以推出i的回文半径也是2
R' C R
c b a b x b a b c
i' i
2). i' 的最左回文边界 在 R' 外 :
i'的回文半径是3,可以推出i的回文半径也是R - i + 1
R' C R
x b a b x b a b c
i' i
3) i' 的最左回文边界在 R' 上 :
i'的回文半径是2,可以推出i的回文半径最短也是2.但是可以往外扩
R' C R
d b a b x b a b x
i' i
三、相关代码如下
char *get_deal_str(char *str)
{
char *buf = malloc(sizeof(char) * strlen(str) * 2 + 1);
memset(buf, '#', sizeof(char) * strlen(str) * 2 + 1);
for (int i = 1; i < strlen(buf); i = i + 2) {
buf[i] = str[ i / 2];
}
return buf;
}
int get_max(int a, int b)
{
return a > b ? a : b;
}
/* 若匹配返回下标,若不匹配返回-1 */
int manager(char *str)
{
if (str == NULL || strlen(str) == 0) {
return -1;
}
char *arr = get_deal_str(str);
int len = strlen(arr);
int R = -1;
int i = 0;
int C = -1;
int max = 0;
int size[len]; /* 求的是回文半径 */
for (i = 0; i < len; i++) {
size[i] = i < R ? get_min(size[2 * C - i], R - i) : 1;
while (i + size[i] < len && i - size[i] >= 0) {
if (arr[i + size[i]] == arr[i - size[i]]) {
size[i]++;
} else {
break;
}
}
if (i + size[i] > R) {
R = i + size[i];
C = i;
}
max = get_max(max, size[i]);
}
return max - 1;
}