2013-team4/code/suffix-array
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
{{{
基数排序的倍增算法, 时间复杂度 O(nlogn)
用法:
build(str, len, sigma);
len 为字符串的普通长度,不包括最后的'\0',其中每个字符的范围是 [0, sigma)
结束后 sa[], rank[], height[] 均得到计算,排序后第一个串不是空串,数组长度均为 len
下标均从 0 开始,height[i] 为 sa[i] 与 sa[i-1] 的 LCP 长度,height[0] 无意义
}}}
{{{
const int N = 100000;
struct SA{
int tmp[2][N], c[N];
int n, sa[N], *rank, height[N];
const char *s;
void getHeight(){
for(int k = 0, i = 0; i < n; i++){
if(rank[i] == 0) continue;
if(k > 0) k--;
int j = sa[rank[i] - 1];
while(s[i + k] == s[j + k]) k++;
height[rank[i]] = k;
}
}
void build(const char *s, int n, int m){
this->n = n; this->s = s;
rank = tmp[0];
memset(c, 0, sizeof(int) * m);
for(int i = 0; i < n; i++) c[rank[i] = s[i]]++;
for(int i = 1; i < m; i++) c[i] += c[i - 1];
for(int i = 0; i < n; i++) sa[--c[rank[i]]] = i;
for(int *t = tmp[1], k = 1; k <= n; k <<= 1){
int p = 0;
for(int i = n - k; i < n; i++) t[p++] = i;
for(int i = 0; i < n; i++) if(sa[i] >= k) t[p++] = sa[i] - k;
//
memset(c, 0, sizeof(int) * m);
for(int i = 0; i < n; i++) c[rank[t[i]]]++;
for(int i = 1; i < m; i++) c[i] += c[i - 1];
for(int i = n - 1; i >= 0; i--) sa[--c[rank[t[i]]]] = t[i];
//
swap(rank, t);
p = 1; rank[sa[0]] = 0;
for(int i = 1; i < n; i++){
int I = sa[i], J = sa[i - 1];
int t1 = (J + k < n ? t[J + k] : -1), t2 = (I + k < n ? t[I + k] : -1);
rank[sa[i]] = (t[J] == t[I] && t1 == t2 ? p - 1 : p++);
}
if(p >= n) break;
m = p;
}
getHeight();
}
};
}}}
基数排序的倍增算法, 时间复杂度 O(nlogn)
用法:
build(str, len, sigma);
len 为字符串的普通长度,不包括最后的'\0',其中每个字符的范围是 [0, sigma)
结束后 sa[], rank[], height[] 均得到计算,排序后第一个串不是空串,数组长度均为 len
下标均从 0 开始,height[i] 为 sa[i] 与 sa[i-1] 的 LCP 长度,height[0] 无意义
const int N = 100000;
struct SA{
int tmp[2][N], c[N];
int n, sa[N], *rank, height[N];
const char *s;
void getHeight(){
for(int k = 0, i = 0; i < n; i++){
if(rank[i] == 0) continue;
if(k > 0) k--;
int j = sa[rank[i] - 1];
while(s[i + k] == s[j + k]) k++;
height[rank[i]] = k;
}
}
void build(const char *s, int n, int m){
this->n = n; this->s = s;
rank = tmp[0];
memset(c, 0, sizeof(int) * m);
for(int i = 0; i < n; i++) c[rank[i] = s[i]]++;
for(int i = 1; i < m; i++) c[i] += c[i - 1];
for(int i = 0; i < n; i++) sa[--c[rank[i]]] = i;
for(int *t = tmp[1], k = 1; k <= n; k <<= 1){
int p = 0;
for(int i = n - k; i < n; i++) t[p++] = i;
for(int i = 0; i < n; i++) if(sa[i] >= k) t[p++] = sa[i] - k;
//
memset(c, 0, sizeof(int) * m);
for(int i = 0; i < n; i++) c[rank[t[i]]]++;
for(int i = 1; i < m; i++) c[i] += c[i - 1];
for(int i = n - 1; i >= 0; i--) sa[--c[rank[t[i]]]] = t[i];
//
swap(rank, t);
p = 1; rank[sa[0]] = 0;
for(int i = 1; i < n; i++){
int I = sa[i], J = sa[i - 1];
int t1 = (J + k < n ? t[J + k] : -1), t2 = (I + k < n ? t[I + k] : -1);
rank[sa[i]] = (t[J] == t[I] && t1 == t2 ? p - 1 : p++);
}
if(p >= n) break;
m = p;
}
getHeight();
}
};