也是白书上来的,白书开了个专题后缀数组,然而这方面我完全不知道。。。于是在今天七夕节来学了一波后缀数组。。。。然后看了一个下午才看懂。。。网上各路大佬的代码我都有看,这里就表明一下主要的转载出处吧:
这一份是让我从不会到会的 : https://www.cnblogs.com/--zz/p/11144860.html
这一个是学height数组的:https://www.cnblogs.com/wsy01/p/6935135.html
这一个是打poj模板题的:https://blog.csdn.net/jeremy1149/article/details/52611995
poj:https://vjudge.net/problem/POJ-2774
说说我的看法吧。
1.sa数组和rnk数组就是一个互逆,原字符串的后缀子串的排名。
2、求sa数组用的是倍增,也就是我一开始不是直接求后缀的,我是求长度为k的子串的排名,在推到k+1的排名的,具体用到基数排序来做。
3.得出来的rnk是从0开始的,注意这一点。然后基数排序时注意有个倒序,具体原因就是旧的sa数组是之前排第二关键字来的,所以得sa数组大的先排,这个yy一下就好了。。
4、然后在求sa的过程中,m(也就是桶的大小是可以优化一下的)。
5.height数组我这里写得是h,h[i]代表着排名为i的后缀子串和排名i-1的后缀子串的最长公共前缀,而又由于这个数组有个性质可以O(n)跑出来。
总复杂度nlogn,因为是倍增log,基数排序O(n)

1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int N=1000000+9; 6 int sa[N],h[N],rnk[N],tem[N],c[N]; 7 char s[N]; 8 void tsort(int k,int n,int m){ 9 for(int i=0;i<m;++i) c[i]=0; 10 for(int i=0;i<n;++i) ++c[ i+k<n ? rnk[i+k] : 0 ]; 11 for(int i=1;i<m;++i) c[i]+=c[i-1]; 12 for(int i=n-1;i>=0;--i) tem[--c[ sa[i]+k<n ? rnk[sa[i]+k] : 0]]=sa[i]; //逆序 13 for(int i=0;i<n;++i) sa[i]=tem[i]; 14 } 15 void get_sa(const char* str){ 16 int n=strlen(str),m=max(n,N),q=0; 17 for(int i=0;i<n;++i) rnk[i]=str[i]; 18 for(int i=0;i<n;++i) sa[i]=i; 19 for(int k=1;k<n;k<<=1){ 20 tsort(k,n,m); 21 tsort(0,n,m); 22 tem[sa[0]]=q=0; 23 for(int i=1;i<n;++i) tem[sa[i]]=(rnk[sa[i]]==rnk[sa[i-1]] && rnk[sa[i]+k]==rnk[sa[i-1]+k])?q:++q; 24 for(int i=0;i<n;++i) rnk[i]=tem[i]; 25 if(q==n-1) break; 26 m=q+1; 27 } 28 for(int i=0;i<n;++i) rnk[sa[i]]=i; 29 } 30 void get_h(const char* str){ 31 int n=strlen(str); 32 int k=0; 33 for(int i=0;i<n;++i){ 34 if(k) --k; 35 // if(rnk[i]==0) continue; 这句删了也行 36 int j=sa[rnk[i]-1]; 37 while(str[j+k]==str[i+k]) ++k; 38 h[rnk[i]]=k; 39 } 40 } 41 int main(){ 42 scanf("%s",s); 43 int len1=strlen(s); 44 s[len1]=1; 45 scanf("%s",s+len1+1); 46 int len=strlen(s); 47 s[len]=0; 48 ++len; 49 get_sa(s); 50 get_h(s); 51 int ans=0; 52 for(int i=2;i<len;++i){ 53 if(ans<h[i]){ 54 if(sa[i-1]>=0&&sa[i-1]<len1&&sa[i]>len1&&sa[i]<len) ans=h[i]; 55 if(sa[i]>=0 && sa[i]<len1 && sa[i-1]>len1 && sa[i-1]<len) ans=h[i]; 56 } 57 } 58 printf("%d",ans); 59 return 0; 60 }