题目链接:http://www.tyvj.cn/p/1860
解题关键:模板题。贴一个代码详解
http://www.cnblogs.com/staginner/archive/2012/02/02/2335600.html
注意:一个字符串中的所有子串都必然是它的后缀的前缀
da算法,必须保证字符串中每个字符的映射>=1
注意点:sa从0~n-1,rank1数组和height数组从1-n
height[1]恒为0
1 #include<cstdlib> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<iostream> 6 #include<cmath> 7 using namespace std; 8 const int N=200005; 9 int wa[N],wb[N],wv[N],wc[N]; 10 bool cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}//比较两个字符串是否完全相同 11 void make_sa(int *r,int *sa,int n,int m){//最大值小于m 12 int i,j,p,*x=wa,*y=wb;//x,y是指针 13 for(i=0;i<m;i++) wc[i]=0; 14 for(i=0;i<n;i++) wc[x[i]=r[i]]++; 15 for(i=1;i<m;i++) wc[i]+=wc[i-1]; 16 for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i;//基数排序 17 for(j=1,p=1;p<n;j*=2,m=p){ 18 for(p=0,i=n-j;i<n;i++) y[p++]=i; 19 for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;//y是第二关键词的sa 20 for(i=0;i<n;i++) wv[i]=x[y[i]]; 21 for(i=0;i<m;i++) wc[i]=0; 22 for(i=0;i<n;i++) wc[wv[i]]++; 23 for(i=1;i<m;i++) wc[i]+=wc[i-1]; 24 for(i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i]; 25 for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;//x是rank数组,1 1 2 2 2 3 这种 26 } 27 return; 28 } 29 int rank1[N],height[N],sa[N];//注意sa和rank的对应关系,sa的数值从0开始,rank的数值从1开始 30 void make_height(int *r,int *sa,int n){ 31 int i,j,k=0; 32 for(i=1;i<=n;i++) rank1[sa[i]]=i; 33 for(i=0;i<n;height[rank1[i++]]=k) 34 for(k?k--:0,j=sa[rank1[i]-1];r[i+k]==r[j+k];k++); 35 return; 36 } 37 //sa是名次所在位置,rank是位置所在名次 38 int r[N<<1]; 39 int main() { 40 ios::sync_with_stdio(0); 41 int n=0; 42 string s; 43 cin>>s; 44 for(int i=0;i<s.size();i++) r[n++]=s[i]-'a'+1; r[n]=0; 45 make_sa(r,sa,n+1,27); 46 make_height(r,sa,n); 47 for(int i=1;i<=n;i++) cout<<sa[i]+1<<" ";cout<<" ";//这里的1是逻辑上的首位 48 for(int i=1;i<=n;i++) cout<<height[i]<<" ";cout<<" "; 49 }
下面这种调用方式更无脑一些
1 #include <cstdlib> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #include<iostream> 6 #include<cstdlib> 7 using namespace std; 8 9 const int N = 200005; 10 int wa[N],wb[N],wv[N],wc[N]; 11 12 bool cmp(int *r,int a,int b,int l){ 13 return r[a]==r[b]&&r[a+l]==r[b+l]; 14 } 15 16 void make_sa(int *r,int *sa,int n,int m){//m是至多有多少个字符,up的意思 17 int i,j,p,*x=wa,*y=wb; 18 for(i=0;i<m;i++) wc[i]=0; 19 for(i=0;i<n;i++) wc[x[i]=r[i]]++; 20 for(i=1;i<m;i++) wc[i]+=wc[i-1]; 21 for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i; 22 for(j=1,p=1;p<n;j*=2,m=p){ 23 for(p=0,i=n-j;i<n;i++) y[p++]=i; 24 for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; 25 for(i=0;i<n;i++) wv[i]=x[y[i]]; 26 for(i=0;i<m;i++) wc[i]=0; 27 for(i=0;i<n;i++) wc[wv[i]]++; 28 for(i=1;i<m;i++) wc[i]+=wc[i-1]; 29 for(i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i]; 30 for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++) 31 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 32 } 33 return; 34 } 35 36 int rank1[N],height[N],sa[N];//输出都是从1开始存的,rank从0开始,最后需要+1,读入从下标0 37 void make_height(int *r,int *sa,int n){ 38 int i,j,k=0; 39 for(i=1;i<=n;i++) rank1[sa[i]]=i; 40 for(i=0;i<n;height[rank1[i++]]=k) 41 for(k?k--:0,j=sa[rank1[i]-1];r[i+k]==r[j+k];k++); 42 return; 43 } 44 //sa是名次所在位置,rank是位置所在名次 45 int r[N]; 46 int main() { 47 ios::sync_with_stdio(0); 48 cin.tie(0); 49 cout.tie(0); 50 string s; 51 cin>>s; 52 for(int i=0;i<s.size();i++) r[i]=(int)s[i]; 53 int t=(int)s.size(); 54 r[t]=0; 55 make_sa(r, sa,t+1,128);//注意+1,因为补0的原因 56 make_height(r, sa, t); 57 for(int i=1;i<=t;i++) cout<<sa[i]+1<<" "; 58 cout<<" "; 59 for(int i=1;i<=t;i++) cout<<height[i]<<" "; 60 cout<<" "; 61 return 0; 62 }
后缀数组练习
poj2774 最长公共子串问题,将两个字符串接在一起解决。height数组就代表lcp(最长公共前缀)
1 #include <cstdlib> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #include<iostream> 6 #include<cstdlib> 7 using namespace std; 8 const int N=200005; 9 int wa[N],wb[N],wv[N],wc[N],n,m; 10 bool cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];} 11 void make_sa(int *r,int *sa,int n,int m){ 12 int i,j,p,*x=wa,*y=wb; 13 for(i=0;i<m;i++) wc[i]=0; 14 for(i=0;i<n;i++) wc[x[i]=r[i]]++; 15 for(i=1;i<m;i++) wc[i]+=wc[i-1]; 16 for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i; 17 for(j=1,p=1;p<n;j*=2,m=p){ 18 for(p=0,i=n-j;i<n;i++) y[p++]=i; 19 for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; 20 for(i=0;i<n;i++) wv[i]=x[y[i]]; 21 for(i=0;i<m;i++) wc[i]=0; 22 for(i=0;i<n;i++) wc[wv[i]]++; 23 for(i=1;i<m;i++) wc[i]+=wc[i-1]; 24 for(i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i]; 25 for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 26 } 27 return; 28 } 29 int rank1[N],height[N],sa[N]; 30 void make_height(int *r,int *sa,int n){ 31 int i,j,k=0; 32 for(i=1;i<=n;i++) rank1[sa[i]]=i; 33 for(i=0;i<n;height[rank1[i++]]=k) 34 for(k?k--:0,j=sa[rank1[i]-1];r[i+k]==r[j+k];k++); 35 return; 36 } 37 38 int r[N<<1]; 39 int main() { 40 ios::sync_with_stdio(0); 41 string s,t; 42 cin>>s>>t; 43 int n=0; 44 for(int i=0;i<s.size();i++) r[n++]=s[i]-'a'+1; r[n++]=27;int sl=n; 45 for(int i=0;i<t.size();i++) r[n++]=t[i]-'a'+1; r[n]=0; 46 make_sa(r, sa, n+1, 28); 47 make_height(r, sa, n); 48 int ans=0; 49 for(int i=1;i<n;i++){ 50 if((sa[i]<sl)!=(sa[i+1]<sl)){ 51 ans=max(ans,height[i+1]); 52 } 53 } 54 cout<<ans<<" "; 55 return 0; 56 }