定义
-
后缀
i :一个字符串从第i 个字符到结尾的子串成为这个字符串的后缀i ; -
后缀排序:将一个字符串的所有后缀按字典序排序;
-
sa[i] :后缀排序后排名第i 的后缀; -
rank[i] :后缀排序后后缀i 的排名; -
最长公共前缀(LCP):两个字符串从头开始最长公共子串的长度;
height[i] :后缀sa[i] 与后缀sa[i-1] 的 LCP ;
后缀排序
后缀排序就是求解
先考虑暴力的方法。快排(
#include <cstdio>
#include <cstring>
const int MAXN=110000;
char a[MAXN];
int n;
int suff[MAXN];
bool cmp(int x, int y)
{
for (int i=0; x+i<=n&&y+i<=n; i++)
if (a[x+i]!=a[y+i]) return a[x+i]<a[y+i];
return x>y;
}
void qsort(int l, int r)
{
int i=l, j=r, mid=suff[l+r>>1];
while (i<=j)
{
while (cmp(suff[i], mid)) i++;
while (cmp(mid, suff[j])) j--;
if (i<=j)
{
int t=suff[i];
suff[i]=suff[j];
suff[j]=t;
i++; j--;
}
}
if (l<j) qsort(l, j);
if (i<r) qsort(i, r);
}
int main()
{
// freopen("sa.in", "r", stdin);
// freopen("sa.out", "w", stdout);
scanf("%s", a+1);
n=strlen(a+1);
for (int i=1; i<=n; i++) suff[i]=i;
qsort(1, n);
for (int i=1; i<=n; i++)
{
for (int j=suff[i]; j<=n; j++)
putchar(a[j]);
putchar('\n');
}
return 0;
}
但这种算法效率明显不高,最多只能跑
常见的后缀排序算法有 倍增 和 DC3 算法,这里主要介绍基于 倍增 的算法。
现在思考一个问题:假设我们已经完成了对所有子串
根据上一轮的排序,我们已经知道了子串
对于这个基数排序的理解,可以用类比的思想,将每个长度为
这一部分的代码:
// 初始化
// 这一部分主要是把所有长度为 1 的子串的排名求出来,相当于初值,直接桶排序即可
memset(st, 0, sizeof st);
memset(rank, 0, sizeof rank);
memset(rank1, 0, sizeof rank1);
for (int i=1; i<=n; i++) st[a[i]]=1;
for (int i=1; i<256; i++) st[i]+=st[i-1];
for (int i=1; i<=n; i++) rank[i]=st[a[i]];
for (int k=0, p=1; k!=n; p<<=1)
{
// 对第一关键字排序
memset(count, 0, sizeof count);
for (int i=1; i<=n; i++) count[rank[i+p]]++;
for (int i=1; i<=n; i++) count[i]+=count[i-1];
for (int i=n; i>=1; i--) tmp[count[rank[i+p]]--]=i;
// 这里的 tmp[i] 表示排名第 i 的子串是 [tmp[i]+p, tmp[i]+2*p)
// 对第二关键字排序
memset(count, 0, sizeof count);
for (int i=1; i<=n; i++) count[rank[i]]++;
for (int i=1; i<=n; i++) count[i]+=count[i-1];
for (int i=n; i>=1; i--) sa[count[rank[tmp[i]]]--]=tmp[i];
// 这里一定记得按 tmp 的反向顺序收集 count 数组
// 计算排名
memcpy(rank1, rank, sizeof rank1);
rank[sa[1]]=k=1;
for (int i=2; i<=n; i++)
{
if (rank1[sa[i]]!=rank1[sa[i-1]]
||rank1[sa[i]+p]!=rank1[sa[i-1]+p]) k++;
// 如果第 i 名与第 i-1 名不同,则当前名次+1
rank[sa[i]]=k;
}
}