1.不连续的子串
翻转一次,转化为求最长公共子序列(LCS),代码略,O(n^2)
2.连续的子串
①枚举start、end,判断是否回文,O(n^3)
②枚举中点(分奇偶情况),向两边延伸,O(n^2)
③后缀树,此处不予讨论
④manacher算法,最高效的方法,O(n)
充分利用了已经算出来的结果:对字符串预处理,逐位扫描,先利用前面基本确定p[i](以i为中心的最长回文串向一个方向延伸的值,p[i]-1正好对应回文串长度)
http://acm.hdu.edu.cn/showproblem.php?pid=3068
#include <cstdio>
#include <cstring>
#include <cstdlib>
const int maxn = 110000+10;
int min(int x, int y) {
return x < y ? x : y;
}
int max(int x, int y) {
return x > y ? x : y;
}
int manacher(char *str, int len) {
int id = 0, maxlen = 0;
int *p = (int *)malloc(2*maxn*sizeof(int));
memset(p, 0, 2*maxn*sizeof(int));
for (int i = 0; i <= 2*len+1; ++i) {
if (id+p[id] > i) {
p[i] = min(p[2*id-i], id+p[id]-i);
} else {
p[i] = 1;
}
while (str[i-p[i]] == str[i+p[i]]) {
++p[i];
}
if (i+p[i] > id+p[id]) {
id = i;
}
maxlen = max(maxlen, p[id]);
}
free(p);
return maxlen-1;
}
int main() {
char *str = (char *)malloc(2*maxn*sizeof(char));
while (scanf("%s", str) == 1) {
int len = strlen(str);
for (int i = len-1; i >= 0; --i) {
str[2*i+2] = str[i];
str[2*i+3] = '#';
}
str[0] = '*'; str[1] = '#'; str[2*len+2] = 0;
printf("%d\n", manacher(str, len));
}
free(str);
return 0;
}