后缀数组练习3:连续重复子串
比前面两个练习题更加简单,只要知道height数组的性质就可以了
1469: 后缀数组3:连续重复子串
时间限制: 1 Sec 内存限制: 128 MB
提交: 101 解决: 57
[提交] [状态] [讨论版] [命题人:admin]题目描述
【问题描述】
求两个字符串的最长公共子串。(长度不超过100000,都是小写字母)
【样例】
输入:yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
yeaphowmuchiloveyoumydearmother
输出:27
不多说,这道题的思路我会引用罗穗骞大佬的论文当中的讲解
简单来说,就是把两个字符串合并,然后用get_he找到他们的最长重复子串,但是要判断是sa是分别属于两个不同的子串里面的
代码实现
1 /*先用个分隔符将两个字符串连接起来,再用后缀数组求出height数组的值, 2 找出一个height值最大并且i与i-1的sa值分别在两串字符中就好*/ 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<algorithm> 7 #include<cmath> 8 #include<iostream> 9 using namespace std; 10 int sa[200020],Rank[200020],rsort[200020]; 11 int cnt[200020],pos[200020],height[200020]; 12 bool cmp(int x,int y,int k){return cnt[x]==cnt[y] && cnt[x+k]==cnt[y+k];} 13 char a[200020],b[200020]; 14 void get_sa(int n,int m) 15 { 16 int k=1,p=0,len; 17 for(int i=1;i<=n;i++) Rank[i]=a[i]; 18 memset(rsort,0,sizeof(rsort)); 19 for(int i=1;i<=n;i++) rsort[Rank[i]]++; 20 for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1]; 21 for(int i=n;i>=1;i--) sa[rsort[Rank[i]]--]=i; 22 for(int k=1;k<n;k<<=1) 23 { 24 len=0; 25 for(int i=n-k+1;i<=n;i++) pos[++len]=i; 26 for(int i=1;i<=n;i++) if(sa[i]>k) pos[++len]=sa[i]-k; 27 for(int i=1;i<=n;i++) cnt[i]=Rank[pos[i]]; 28 memset(rsort,0,sizeof(rsort)); 29 for(int i=1;i<=n;i++) rsort[cnt[i]]++; 30 for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1]; 31 for(int i=n;i>=1;i--) sa[rsort[cnt[i]]--]=pos[i]; 32 for(int i=1;i<=n;i++) cnt[i]=Rank[i]; 33 p=1; Rank[sa[1]]=1; 34 for(int i=2;i<=n;i++) 35 { 36 if(!cmp(sa[i],sa[i-1],k)) p++; 37 Rank[sa[i]]=p; 38 } 39 m=p; 40 } 41 a[0]=0; sa[0]=0; 42 } 43 void get_he(int n) 44 { 45 int j,k=0; 46 for(int i=1;i<=n;i++) 47 { 48 j=sa[Rank[i]-1]; 49 if(k) k--; 50 while(a[j+k]==a[i+k]) k++; 51 height[Rank[i]]=k; 52 } 53 } 54 int main() 55 { 56 scanf("%s",a+1); scanf("%s",b+1); 57 int n=strlen(a+1),m=strlen(b+1); 58 a[n+1]='T';/*分隔符*/ 59 for(int i=n+2;i<=n+m+1;i++) a[i]=b[i-n-1];/*目前总长度为n+m+1,合并字符串的操作*/ 60 get_sa(n+m+1,256); get_he(n+m+1);/*一串的ASCII码为128,两串就是256*/ 61 int ans=0; 62 for(int i=2;i<=n+m+1;i++) 63 if((sa[i-1]<=n && sa[i]>n+1) || (sa[i-1]>n+1 && sa[i]<=n))/*保证sa分别在两串当中*/ 64 ans=max(ans,height[i]);/*更新最大值*/ 65 printf("%d\n",ans); 66 return 0; 67 }
我们最终都要成长,最终都要和稚嫩的自己告别.