算法介绍
- 后缀数组是用来解决⼀类字符串问题的⼯具
- 算法目标是计算出字符串的每个后缀的排名
- 几个要用到的定义
- n : 字符串的长度
- sz : 字符集
- s : 字符串,方便起见,我们从0开始标号,即 s[0]~s[n-1]
- suf[i] : 下标从i开始的后缀
- rk[i] : 以 s[i] 开头的后缀的排名为rk[i]
- sa[i] : 即排名为i的后缀从sa[i]开始
- 原理
- 桶排
- 按照2的幂次倍增
- 将后缀分成前后两个等长的部分,先将所有后缀按照前半部分排序,完成后 再将后半部分考虑进去,两部分结果合并完成最终的排序
- 如下图
最长公共前缀
- rk[i]表示后缀 i 的排名,height[i]表示 排名为i的和排名为i-1的LCP长度。对于两个前缀 j 和 k,j>k,不妨设rk[j]<rk[k],不难得到,后缀j和k的LCP长度等于 MIN{ height[rk[j]+1], height[rk[j]+2],.........,height[rk[k]] },如下图
- 根据定义,每次计算一个height数组,都需要O(n),则共需要O(n^2),还可以进行优化
- 再用个辅助数组h[i]=height[rank[i]],然后按照h[1],h[2]……h[n]的顺序递推计算, 递推的关键在于这样一个性质:h[i]>=h[i-1]-1
int getheight() {
int k=0;
rep(i,0,n-1) rk[sa[i]]=i;
rep(i,0,n-1) {
if (rk[i]==0) continue;//第一名height为0
if (k) --k;//h[i]>=h[i-1]-1;
int j=sa[rk[i]-1];
while (j+k<=n && i+k<=n && s[i+k]==s[j+k]) ++k;
h[i]=height[rk[i]]=k;//h[i]=height[rk[i]];
}
}
- 证明
- 设排在后缀i-1前一个的是后缀 k,后缀 k 和后缀 i-1 分别删除首字符之后得到后缀 k+1和后缀 i,因此后缀 k+1一定排在后缀 i 的前面,并且它们的最长公共点缀长度为h[i-1]-1,如图所示:
- 这个h[i-1]-1是一系列h值的最小值,这些h值包括后缀i和排在它前一个的后缀p的LCP长度,即h[i],因此h[i]>=h[i-1]-1。
Code
void SA(){
int sz=max(n,300);
rep(i, 0, n-1 ) rk[i]=s[i];
rep(i, 0, n-1 ) ++bin[rk[i]];
rep(i, 1, sz-1) bin[i]+=bin[i-1];
rep(i, 0, n-1 ) sa[--bin[rk[i]]]=i;
for(int j=1;j<=n;j*=2)
{
int p=0;
per(i, n-1, n-j ) tmp[p++]=i;
rep(i, 0, n-1 ) if(sa[i]-j>=0)tmp[p++]=sa[i]-j;//Attention
rep(i, 0, sz-1) bin[i]=0;
rep(i, 0, n-1 ) ++bin[rk[i]];
rep(i, 1, sz-1) bin[i]+=bin[i-1];
per(i, n-1, 0 ) sa[--bin[rk[tmp[i]]]]=tmp[i];//Attention
p=tmp[sa[0]]=0;
rep(i,1,n-1){
int v0=sa[i-1],v1=sa[i],v00,v01;
if (v0 + j < n) v00 = rk[v0 + j]; else v00 = -1 ;//Attention
if (v1 + j < n) v01 = rk[v1 + j]; else v01 = -1 ;//Attention
if(rk[v0]==rk[v1] && v00==v01) tmp[v1]=p;//Attention
else tmp[v1]=++p;
}
rep( i, 0, n-1 ) rk[i]=tmp[i];
}
}
int getheight() {
int k=0;
rep(i,0,n-1) rk[sa[i]]=i;
rep(i,0,n-1) {
if (rk[i]==0) continue;
if (k) --k;
int j=sa[rk[i]-1];
while (j+k<n && i+k<n && s[i+k]==s[j+k]) ++k;//Attention
h[i]=height[rk[i]]=k;
}
}
练习
- UOJP35后缀排序
- POJ2774 LongLongMessage
- SPOJ - SUBST1 New Distinct Substrings
- USACO 2006 December Milk Patterns