【模板】poj2774后缀数组

≡放荡痞女 提交于 2019-11-26 08:59:44

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

这一份是让我从不会到会的 : 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 }
View Code

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!