【算法简介】
【定义】
后缀数组是一个维护序列所有后缀的算法,具体的维护每一个后缀在所有后缀中的排名rk,和它的逆数组sa表示排名为i的数组开头是sa[i]位
以及题目中最常应用的height数组,表示排名为i和排名为i-1两个后缀的最长公共前缀
【操作】
1.calcsa
计算sa和rk数组,主要是基于计数排序来实现倍增的计算排名
具体实现理解了之后就是背板子了
bool cmp(int x,int y,int w)
{
return oldrk[x]==oldrk[y] && oldrk[x+w]==oldrk[y+w];
}
void calcsa()
{
int m=233;
for(int i=0;i<=m;i++) cnt[i]=0;
for(int i=1;i<=n;i++) cnt[rk[i]=a[i]]++;
for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--) sa[cnt[rk[i]]--]=i;
int i,p;
for(int w=1;;w<<=1,m=p)
{
for(p=0,i=n;i>n-w;i--) id[++p]=i;
for(i=1;i<=n;i++) if(sa[i]>w) id[++p]=sa[i]-w;
for(i=0;i<=m;i++) cnt[i]=0;
for(i=1;i<=n;i++) cnt[fz[i]=rk[id[i]]]++;
for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
for(i=n;i>=1;i--) sa[cnt[fz[i]]--]=id[i];
for(i=1;i<=n;i++) oldrk[i]=rk[i];
for(p=0,i=1;i<=n;i++) rk[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p;
if(p==n)
{
for(i=1;i<=n;i++) sa[rk[i]]=i;
break;
}
}
}
2.calch
计算height数组,类似尺取的思想去计算即可
void calch()
{
int i,k=0;
for(i=1;i<=n;i++)
{
if(k) k--;
while(a[i+k]==a[sa[rk[i]-1]+k]) k++;
h[rk[i]]=k;
}
}
【应用】
1.poj1743 Musical Theme
最长的相似不重叠子串,这里相似定义为两个串每次字符对应的差值相同
2.poj3294 Life Forms
求出现次数超过一半的最长子串
3.poj3261 Milk Patterns
求重复k次可重叠子串长度
4.SPOJ694 Distinct Substrings
求不相同的子串的个数
5.poj2406 Power Strings
字符串从头开始最多有多少个重复片段
6.ural1297 palindrome
求最长回文子串
7.poj2774 Long Long Message
两个串的最长公共连续子串
本文介绍了后缀数组的基本概念,包括rk数组的定义与计算方法(通过计数排序实现倍增),以及height数组的计算。通过实际应用案例如MusicalTheme、LifeForms等展示后缀数组在字符串处理中的关键作用。
3001

被折叠的 条评论
为什么被折叠?



