以下内容均取自挑战程序设计竞赛
目录
1.后缀数组的计算:
int n,k;
int rankk[maxn+1];
int tmp[maxn+1];
//sa[i]表示排在第i的字符串起始字母的下标。
//rank[i]表示从第i位字母开始的后缀排在第几。
bool compare_sa(int i,int j){
if(rankk[i]!=rankk[j]){
return rankk[i]<rankk[j];
}else{
int ri=i+k<=n?rankk[i+k]:-1;
int rj=j+k<=n?rankk[j+k]:-1;
return ri<rj;
}
}
void construct_sa(string s,int *sa){
n=s.size();
for(int i=0;i<=n;i++){
sa[i]=i;
rankk[i]=i<n?s[i]:-1;
}
for(k=1;k<=n;k<<=1){
sort(sa,sa+n+1,compare_sa);
tmp[sa[0]]=0;
for(int i=1;i<=n;i++){
tmp[sa[i]]=tmp[sa[i-1]]+(compare_sa(sa[i-1],sa[i])?1:0);
}
for(int i=0;i<=n;i++){
rankk[i]=tmp[i];
}
}
}
2.基于后缀数组的字符串匹配:
KMP复杂度为,后缀数组为
,所以在
比较大时,后缀数组更高效,同时对同一个字符串多次匹配时,后缀数组更高效。
bool contain(string s,int *sa,string t){
int a=0,b=s.size();
while(b-a>1){
int c=(a+b)>>1;
if(s.compare(sa[c],t.size(),t)<0) a=c;
else b=c;
}
return s.compare(sa[b],t.length(),t)==0;
}
3.高度数组(LCP Array)
表示后缀
和后缀
的最长公共前缀的长度位
void construct_lcp(string s,int *sa,int *lcp){
int n=s.size();
for(int i=0;i<=n;i++){
rankk[sa[i]]=i;
}
int h=0;
lcp[0]=0;
for(int i=0;i<n;i++){
int j=sa[rankk[i]-1];
if(h) h--;
for(;j+h<n&&i+h<n;h++){
if(s[j+h]!=s[i+h]) break;
}
lcp[rankk[i]-1]=h;
}
}
将rmq(区间查询)与后缀数组结合,可以计算任意两个后缀的最长公共前缀。
后缀的公共前缀长度为
4.应用
1).字符串匹配
2).计算最长公共子串。例题
3).计算最长回文子串。例题