也是白书上来的,白书开了个专题后缀数组,然而这方面我完全不知道。。。于是在今天七夕节来学了一波后缀数组。。。。然后看了一个下午才看懂。。。网上各路大佬的代码我都有看,这里就表明一下主要的转载出处吧:
这一份是让我从不会到会的 : 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 }
