两道回文串的题目,关于回文串的题目有很多种解法。以前写回文串的题目都是采用后缀数组写的,今天无意中搜到了Manacher算法,就学了一下。发现Manacher算法真心简洁,复杂度低编程量低。后缀数组写起来得100来行的题目,Manacher写起来不到30行,无限ORZ。。。关于Manacher算法:http://wenku.baidu.com/view/3031d2d3360cba1aa811da42.html
直接看这里就明白了。不过这个文档上的提供的HDOJ3068的代码有点问题。比如数据:
aaaa
aaa
答案两个都是4,n值计算错误,应该为n = 1<hdu3068采用了比较快的getchar()读入后,也就跑了250ms,不知道那些跑了100+ms的是怎么写的,ORZ。。。。。。
hdu3068
#include
#define L 110010
char a[L<<1];
int p[L<<1];
int min(int a, int b){
if(a < b) return a;
return b;
}
int main(){
int i, n, id, MaxL, MaxId;
char ch;
while((ch=getchar())!=EOF){
n = 4;
a[0] = '$', a[1] = '#';
a[2] = ch , a[3] = '#';
while((ch = getchar())!='\n'){
a[n ++] = ch, a[n ++] = '#';
}
a[n] = 0;
MaxL = MaxId = 0;
for(i = 1; i < n; i ++){
if(MaxId > i)
p[i] = min(p[2*id - i], MaxId - i);
else p[i] = 1;
while(a[i+p[i]]==a[i-p[i]]) p[i] ++;
if(p[i] + i > MaxId)
MaxId = p[i] + i, id = i;
if(p[i] > MaxL)
MaxL = p[i] ;
}
printf("%d\n", MaxL - 1);
}
}
后缀数组版:
#include
#include
#define maxn 2005
char s[maxn];
int r[maxn], sa[maxn], rank[maxn], height[maxn];
int wa[maxn], wb[maxn], wv[maxn], ws[maxn];
bool cmp(int *arr, int x, int y, int l){
return arr[x]==arr[y]&&arr[x+l]==arr[y+l];
}
void da(int *r, int *sa, int n, int m){
int i, j, p, *x = wa, *y = wb, *t;
for(i = 0; i < m; i ++) ws[i] = 0;
for(i = 0; i < n; i ++) ws[x[i]=r[i]] ++;
for(i = 1; i < m; i ++) ws[i] += ws[i-1];
for(i = n-1; i >= 0; i --) sa[--ws[x[i]]] = i;
for(j = 1; j <= n; j<<=1){
for(p = 0, i = n - j; i < n; i ++) y[p ++] = i;
for(i = 0; i < n; i ++) if(sa[i] >= j) y[p ++] = sa[i] - j;
for(i = 0; i < m; i ++) ws[i] = 0;
for(i = 0; i < n; i ++) ws[wv[i] = x[y[i]]] ++;
for(i = 1; i < m; i ++) ws[i] += ws[i-1];
for(i = n-1; i >= 0; i --) sa[--ws[wv[i]]] = y[i];
t = x, x = y, y = t;
p = 1, x[sa[0]] = 0;
for(i = 1; i < n; i ++)
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1 : p ++;
if(p >= n)
break;
m = p;
}
}
void calcHeight(int *r, int *sa, int n){
int i, j, k = 0;
for(i = 1; i <= n; i ++) rank[sa[i]] = i;
for(i = 0; i < n; height[rank[i ++]] = k)
for(k?k--:0, j = sa[rank[i]-1]; r[i+k]==r[j+k]; k ++);
}
int min(int x, int y){
return x < y ? x : y;
}
//mm[i] = log(i)
int RMQ[maxn][15], mm[maxn];
void initRMQ(int n){
int i, j, a, b;
for(mm[0] = -1, i = 1; i < maxn; i ++){
mm[i] = (i&(i-1)) == 0 ? mm[i-1] + 1 : mm[i-1];
}
for(i = 1; i <= n; i ++) RMQ[i][0] = height[i];
for(j = 1; (1< b) t = a, a = b, b = t;
return query(a + 1, b);
}
int main(){
int i, n, len, ans, tmp, loc;
scanf("%s", s);
len = strlen(s);
for(i = 0; i < len; i ++) r[i] = s[i];
r[len] = 1;
for(i = 0; i < len; i ++) r[i + len + 1] = s[len - i - 1];
n = len * 2 + 1;
r[n] = 0;
da(r, sa, n + 1, 129);
calcHeight(r, sa, n);
initRMQ(n);
ans = 0;
loc = -1;
for(i = 0; s[i]; i++){
tmp = lcp(i, n - i);
if(ans < 2 * tmp) ans = 2 * tmp , loc = i - tmp;
tmp = lcp(i, n - i- 1);
if(ans < 2 * tmp - 1) ans = 2 * tmp - 1,loc = i - tmp + 1;
}
s[ans + loc] = 0;
printf("%s\n", s+loc);
return 0;
}
Manacher版
#include
#define M 2010
char a[M];
int p[M];
int min(int a,int b){
return a < b ? a : b;
}
int main(){
char ch;
int i, n, id, MaxL, MaxId, loc;
a[0] = '$', a[1] = '#', n = 2;
while((ch=getchar())!='\n'){
a[n ++] = ch, a[n ++] = '#';
}
MaxL = MaxId = 0, a[n] = 0;
for(i = 1; i < n; i ++){
if(i < MaxId) p[i] = min(p[2*id-i], MaxId - i);
else p[i] = 1;
while(a[i+p[i]] ==a[i-p[i]]) p[i]++;
if(i+p[i] > MaxId) MaxId = i + p[i] , id = i;
if(p[i] > MaxL) MaxL = p[i], loc = i;
}
for(i = loc - MaxL + 1; i < loc + MaxL; i ++)
if(a[i]!='#') putchar(a[i]);
}