#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define maxn 200010
using namespace std;
char str[maxn];
int sa[maxn],wx[maxn],wy[maxn],w[maxn],wv[maxn],Rank[maxn],height[maxn],s[maxn];
//sa[i]表示第i大的子串的下标,Rank[i]表示子串下标i的排名,height[i]表示sa[i]与sa[i-1]的最长公共前缀
//sa[i]有效范围(i>=1&&i<=n)sa[0]=n,Rank[i]有效范围(i>=0&&i<n)Rank[n]=0,height[i]有效范围(i>=1&&i<=n)height[1]=0
int cmp(int *r ,int a ,int b, int j)//比较字符串是否相等
{
return (r[a]==r[b])&&(r[a+j]==r[b+j]);
}
void da(int *r , int n , int m)
{
int i,j,p,*x=wx,*y=wy,*t;
for(i=0;i<m;i++)//基数排序
w[i]=0;
for(i=0;i<n;i++)
w[x[i]=r[i]]++;
for(i=1;i<m;i++)
w[i]+=w[i-1];
for(i=n-1;i>=0;i--)
sa[--w[x[i]]]=i;
for(j=1,p=0;p<n;j*=2,m=p)//m为基数排序的参数
{
for(p=0,i=n-j;i<n;i++)//第二关键字排序
y[p++]=i;
for(i=0;i<n;i++)
if(sa[i]>=j)
y[p++]=sa[i]-j;
for(i=0;i<n;i++)
wv[i]=x[y[i]];
for(i=0;i<m;i++)//第一第二关键字组合之后的基数排序
w[i]=0;
for(i=0;i<n;i++)
w[wv[i]]++;
for(i=1;i<m;i++)
w[i]+=w[i-1];
for(i=n-1;i>=0;i--)
sa[--w[wv[i]]]=y[i];
for(p=1,i=1,t=x,x=y,y=t,x[sa[0]]=0;i<n;i++)//求出x[]为下一次第一关键字的顺序
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}
void calheight(int * r , int n)//求height[]
{
int i,k=0,j;
for(i=1;i<=n;i++)
{
if(i==1)
printf("%d",sa[i]+1);
else
printf(" %d",sa[i]+1);
Rank[sa[i]]=i;//Rank和sa相反
}
cout<<endl;
for(i=0;i<n;height[Rank[i++]]=k)
for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);
cout<<height[1];
for(i=2;i<=n;i++)
{
printf(" %d",height[i]);
}
cout<<endl;
}
int main()
{
while(scanf("%s",str)!=EOF)
{
int len=strlen(str);
for(int i=0; i<len; i++)//把字符转化为整形
s[i]=str[i];
s[len]=0;
da(s,len+1,128);//多了一个s[len],长度加1
calheight(s,len);
}
return 0;
}
后缀数组模板(倍增法)
最新推荐文章于 2021-08-05 11:27:12 发布