后缀数组
Posted lhm-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了后缀数组相关的知识,希望对你有一定的参考价值。
将字符串每个后缀按照字典序排序
(sa:)表示排名为(i)的后缀的起始位置
(rk:)表示起始位置为(i)的后缀的排名
(sa[rk[i]]=i, rk[sa[i]]=i)
通过倍增和基数排序来实现(O(n log n))的排序
基数排序时先排第一关键字,再在第一关键字相同下排第二关键字
第二关键字本身是有序的
(num:)表示当前排名的个数,也就是可以存在并列(当一二关键字都相等时),当(num=n)是就排好序了
(tp:)表示排名为(num)的后缀的位置,也是第二关键字排名为(i)的后缀的起始位置
(rk[tp[i]])即为排名为(i)的第二关键字对应的第一关键字
(b[rk[tp[i]]])即为当第一关键字相同时,第二关键字较大的该后缀的排名
所以(sa[b[rk[tp[i]]]--]=tp[i])
(rk)和(tp)数组大小应开成两倍
(LCP)最长公共前缀
(ht:)表示(suff(sa[i]))和(suff(sa[i-1]))的最长公共前缀
(h:)表示(ht[rk[i]]),(suff(i))和排序后它前一位的后缀的最长公共前缀
(h[i] geqslant h[i-1]-1)
所以(suff(i))和它前一位后缀的最长公共前缀至少为(h[i-1]-1)
(code:)
void rsort()
{
for(int i=0;i<=m;++i) b[i]=0;
for(int i=1;i<=n;++i) b[rk[i]]++;
for(int i=1;i<=m;++i) b[i]+=b[i-1];
for(int i=n;i;--i) sa[b[rk[tp[i]]]--]=tp[i];
}
void SA()
{
for(int i=1;i<=n;++i) rk[i]=str[i],tp[i]=i;
rsort();
for(int k=1;k<=n;k<<=1)
{
int num=0;
for(int i=n-k+1;i<=n;++i) tp[++num]=i;
for(int i=1;i<=n;++i)
if(sa[i]>k)
tp[++num]=sa[i]-k;
rsort();
memcpy(tp,rk,sizeof(rk));
rk[sa[1]]=num=1;
for(int i=2;i<=n;++i)
rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k])?num:++num;
if(num==n) break;
m=num;
}
}
void height()
{
int k=0;
for(int i=1;i<=n;++i) rk[sa[i]]=i;
for(int i=1;i<=n;++i)
{
if(rk[i]==1) continue;
if(k) k--;
int j=sa[rk[i]-1];
while(str[i+k]==str[j+k]) k++;
ht[rk[i]]=k;
}
}
以上是关于后缀数组的主要内容,如果未能解决你的问题,请参考以下文章