嘿嘿,用大牛的代码过的,我觉得,要理解这个好难呀,但要是用了模板计算后缀数组sa[],名次数组rank[],还有height[],height[]是后缀数组的关键所在,用来模板计算出这三个数组,后缀数组的应用也就拓展得开了哦
看下模板吧,不过这个版本用了657ms耶,不是很快的说
#include <iostream> using namespace std; #define MAXN 200010// max{str.len,256} int b[MAXN],array[4][MAXN],*rank1,*nrank,*sa,*nsa,height[MAXN],n,len; char str[MAXN],str1[MAXN/2]; void make_sa(){ int i,k; n=strlen(str); sa=array[0]; nsa=array[1]; rank1=array[2]; nrank=array[3]; //求sa_1 //计数排序 memset(b,0,sizeof(b)); for(i=0;i<n;i++) b[str[i]]++; for(i=1;i<=256;i++) b[i]+=b[i-1]; for(i=n-1;i>=0;i--)//str[i] sa[--b[str[i]]]=i; //求rank_1 for(rank1[sa[0]]=0,i=1;i<n;i++){//sa[i] rank1[sa[i]]=rank1[sa[i-1]]; if(str[sa[i]]!=str[sa[i-1]]) rank1[sa[i]]++; } for(k=1;k<n && rank1[sa[n-1]]<n-1;k*=2){ //求sa_2k //桶排序 //只保存每个桶的尾部后缀的编号作为索引(编号为i的后缀即suffix(sa[i]))。 //注意到在sa_n和rank_n构造完毕之前,sa_k和rank_k不一定是互为反函数: //sa-k[i]=j总是双射;rank-k[i]=j可能存在多个i映射到一个j上。 //反映到算法上就是所有k前缀相等的后缀都放在一个桶内。 for(i=0;i<n;i++)//sa[i] b[rank1[sa[i]]]=i; //基数排序 //由于2k前缀的后半段已排好序,对所有后缀的2k前缀的排序结果就是对2k前缀 //的前半段的稳定排序结果。 //注意到一个后缀的2k前缀的前半段实质是某一个后缀的k前缀,所有后缀的k前 //缀的排序结果已由桶排得到 for(i=n-1;i>=0;i--)//sa[i] if(sa[i]-k>=0) nsa[b[rank1[sa[i]-k]]--]=sa[i]-k; //长度不足2k的后缀的编号不变 for(i=n-k;i<n;i++)//i=sa[j] nsa[b[rank1[i]]--]=i; //求rank_2k for(nrank[nsa[0]]=0,i=1;i<n;i++){//nsa[i] nrank[nsa[i]]=nrank[nsa[i-1]]; //仅当两个2k前缀的前半部分和后半部分分别对应相等时两个2k前缀相等 if(rank1[nsa[i]]!=rank1[nsa[i-1]] || rank1[nsa[i]+k]!=rank1[nsa[i-1]+k]) nrank[nsa[i]]++; } int *t=sa;sa=nsa;nsa=t; t=rank1;rank1=nrank;nrank=t; } } void cal_height(){//height[i]定义为LCP(i-1,i),表示名次为i-1和名次为i的后缀的lcp int i,j,k; //rank和sa互为反函数 for(i=0,k=0;i<n;i++){//str[i] if(rank1[i]==0) height[rank1[i]]=0; else{ for(j=sa[rank1[i]-1];str[i+k]==str[j+k];k++); height[rank1[i]]=k;//k为当前h[sa[i]]的值 if(k>0) k--; } } } int main(){ int i,p1,p2,ans; while(scanf("%s%s",str,str1)!=EOF){ //构造"str#str1$" len=strlen(str); str[len]='#'; str[len+1]='\0'; strcat(str,str1); n=strlen(str); str[n++]='$'; str[n]='\0'; make_sa(); cal_height(); ans=0; for(i=1;i<n;i++){ if(sa[i]<len) p1=1; else p1=-1; if(sa[i-1]<len) p2=1; else p2=-1; if(p1*p2<1 && height[i]>ans) ans=height[i]; } printf("%d\n",ans); } return 0; }
另一个模板哦,更快一点
#include <stdio.h> #include <stdlib.h> #include <string.h> int const N= 201000; int wa[N], wb[N], ws[N], wv[N]; int sa[N], height[N], rank[N], n,r[N]; char str[N],str1[N]; int cmp( int* r, int a, int b, int L ){ return r[a]== r[b] && r[a+ L]== r[b+ L]; } void da( int* r, int* sa, int n, int m ){ int i, j, p, *x= wa, *y= wb, *t; for( i= 0; i< m; ++i ) ws[i]= 0; for( i= 0; i< n; ++i ) ws[ x[i]= r[i] ]++; for( i= 1; i< m; ++i ) ws[i]+= ws[i-1]; for( i= n- 1; i>= 0; i-- ) sa[ --ws[ x[i] ] ]= i; for( j= 1, p= 1; p< n; j*= 2, m= p ){ for( p= 0, i= n- j; i< n; ++i ) y[p++]= i; for( i= 0; i< n; ++i ) if( sa[i]>= j ) y[p++]= sa[i]- j; for( i= 0; i< n; ++i ) wv[i]= x[y[i]]; for( i= 0; i< m; ++i ) ws[i]= 0; for( i= 0; i< n; ++i ) ws[ wv[i] ]++; for( i= 1; i< m; ++i ) ws[i]+= ws[i-1]; for( i= n- 1; i>= 0; i-- ) sa[ --ws[ wv[i] ] ]= y[i]; t= x, x= y, y= t, p= 1; x[ sa[0] ]= 0; for( i= 1; i< n; ++i ) x[ sa[i] ]= cmp( y, sa[i-1], sa[i], j )? p- 1: p++; } } void callheight( int* r, int*sa, int n ){ int i, j, k= 0; for( i= 1; i<= n; ++i ) rank[ sa[i] ]= i; for( i= 0; i< n; height[ rank[i++] ]= k ) for( k?k--:0, j= sa[ rank[i]- 1]; r[i+k]== r[j+k]; k++ ); } int main(){ int i,p1,p2,ans,len1,len2; while(scanf("%s%s",str,str1)!=EOF){ len1=strlen(str); for(i=0;i<len1;i++) r[i]=static_cast<int>(str[i]); r[len1]=1; len2=strlen(str1); for(i=0;i<len2;i++) r[len1+i+1]=static_cast<int>(str1[i]); r[len1+len2+1]=0; da(r,sa,len1+len2+2,256); callheight(r,sa,len1+len2+1); ans=0; n=len1+len2+1; for(i=1;i<=n;i++){ if(sa[i]<len1) p1=1; else p1=-1; if(sa[i-1]<len1) p2=1; else p2=-1; if(p1*p2<1 && height[i]>ans) ans=height[i]; } printf("%d\n",ans); } return 0; }