下面就是我研究了09年穗骞的论文中代码之后自己修改的,思路是一样的,只不过对变量的命名更加容易理解罢了,还加了详细的注释,我也只能做这么多了,要是还不理解我也没办法了!
#define _N 200010 struct SuffixArray { //SuffixArray::none static char const NONE='z'+1;//所有字符都不出现的 int *r,*rank,*c,*sa,*secondSa,*first,*height; //r[i]为输入数据从r[i]>=0 //rank[i]保存每一趟排序后的下标i名次 //secondSa[i]保存名次为i第二关键字的下标 //first[i]在第二关键字排名为i的条件下第一关键字的排名 int n,up;//上界r[i]<up void init() { r=new int[_N]; rank=new int[2*_N]; c=new int[_N];//开辟的空间原则上应该是字符中最大值 sa=new int[_N]; secondSa=new int[2*_N]; first=new int[_N]; height=new int[_N]; } void input(string s) { n=s.size(); up=0; for(int i=0; i<n; i++) { r[i]=s[i]-'a';//纯字母字符串 if(up<r[i])up=r[i]; } up++; r[n]=up;//末尾与所有字符不同,用于height数组的计算 } bool cmp(int *rank,int a,int b,int delta) { return rank[a]==rank[b] && rank[a+delta]==rank[b+delta]; } void calSA() { for(int i=0; i<2*n; i++)rank[i]=secondSa[i]=-1; //cmp函数比较第1,2关键字时避免越界的 //判断开2倍空间并且赋值比所有排名还低的排名(因为这个时无效排名) //计数排序初使化sa[],rank[] for(int i=0; i<up; i++)c[i]=0; for(int i=0; i<n; i++) c[rank[i]=r[i]]++; for(int i=1; i<up; i++)c[i]+=c[i-1]; for(int i=n-1; i>-1; i--)sa[--c[rank[i]]]=i; //从大到小 int p=0;//p<n都可(进入循环的条件) for(int halfLen=1; p<n; halfLen<<=1,up=p) {//倍增时每个字符串的长度的一半为halfLen p=0;//此处初使化的含义和上面的循环条件不同 //p此处的含义是对secondSa下标的初使化 //循环里的条件的含义是最大的名次如果等于n //则rank[0,1……n-1]已经唯一了,不需要继续执行了 for(int i=n-halfLen; i<n; i++)secondSa[p++]=i; //超出范围的下标按下标顺序置其名次为最低(稳定排序) for(int i=0; i<n; i++)if(sa[i]>=halfLen)secondSa[p++]=sa[i]-halfLen; //含义是名次为上次排名为i的的序号对应于第二关键字的序号为:sa[i]-halfLen for(int i=0; i<n; i++)first[i]=rank[secondSa[i]]; //在第二关键字排名为i的条件下第一关键字的排名 for(int i=0; i<up; i++)c[i]=0;//这里上界不是n而是up for(int i=0; i<n; i++)c[first[i]]++; for(int i=1; i<up; i++)c[i]+=c[i-1]; for(int i=n-1; i>-1; i--)sa[--c[first[i]]]=secondSa[i]; //从大到小(第二关键字已经是有序) int *tmp,i; for(tmp=rank,rank=secondSa,secondSa=tmp,rank[sa[0]]=0,i=p=1; i<n; i++) {//rank[]其实是根据它自己进行计算 rank[sa[i]]=cmp(secondSa,sa[i],sa[i-1],halfLen)?p-1:p++; //最后一个字符的用处sa[i]+halLen或sa[i-1]+halfLen会越界!! //重新筛出排名相等的下标 //若第一,二关键字都不同则排名应该+1 } } } void calHeight() { //根据性质h[i]>=h[i-1]-1,height[rank[i]]=h[i]依次计算出h[0],h[1],……h[n-1] int preRankLable,preLen=0; //preRankLable表示前一名的下标 //preLen表示下标为cur-1的长度 for(int cur=0; cur<n; cur++) { if(rank[cur]) { for(preLen?--preLen:0,preRankLable=sa[rank[cur]-1]; r[cur+preLen]==r[preRankLable+preLen]; preLen++); height[rank[cur]]=preLen; } else height[0]=preLen=0; } } } suffixArray;
#include<cstdio> #include<cstring> #include<iostream> using namespace std; // freopen("data.in","r",stdin); #define _N 200010 struct SuffixArray { //SuffixArray::none static char const NONE='z'+1;//所有字符都不出现的 int *r,*rank,*c,*sa,*secondSa,*first,*height; //r[i]为输入数据从r[i]>=0 //rank[i]保存每一趟排序后的下标i名次 //secondSa[i]保存名次为i第二关键字的下标 //first[i]在第二关键字排名为i的条件下第一关键字的排名 int n,up;//上界r[i]<up void init() { r=new int[_N]; rank=new int[2*_N]; c=new int[_N];//开辟的空间原则上应该是字符中最大值 sa=new int[_N]; secondSa=new int[2*_N]; first=new int[_N]; height=new int[_N]; } void input(string s) { n=s.size(); up=0; for(int i=0; i<n; i++) { r[i]=s[i]-'a';//纯字母字符串 if(up<r[i])up=r[i]; } up++; r[n]=up;//末尾与所有字符不同,用于height数组的计算 } bool cmp(int *rank,int a,int b,int delta) { return rank[a]==rank[b] && rank[a+delta]==rank[b+delta]; } void calSA() { for(int i=0; i<2*n; i++)rank[i]=secondSa[i]=-1; //cmp函数比较第1,2关键字时避免越界的 //判断开2倍空间并且赋值比所有排名还低的排名(因为这个时无效排名) //计数排序初使化sa[],rank[] for(int i=0; i<up; i++)c[i]=0; for(int i=0; i<n; i++) c[rank[i]=r[i]]++; for(int i=1; i<up; i++)c[i]+=c[i-1]; for(int i=n-1; i>-1; i--)sa[--c[rank[i]]]=i; //从大到小 int p=0;//p<n都可(进入循环的条件) for(int halfLen=1; p<n; halfLen<<=1,up=p) {//倍增时每个字符串的长度的一半为halfLen p=0;//此处初使化的含义和上面的循环条件不同 //p此处的含义是对secondSa下标的初使化 //循环里的条件的含义是最大的名次如果等于n //则rank[0,1……n-1]已经唯一了,不需要继续执行了 for(int i=n-halfLen; i<n; i++)secondSa[p++]=i; //超出范围的下标按下标顺序置其名次为最低(稳定排序) for(int i=0; i<n; i++)if(sa[i]>=halfLen)secondSa[p++]=sa[i]-halfLen; //含义是名次为上次排名为i的的序号对应于第二关键字的序号为:sa[i]-halfLen for(int i=0; i<n; i++)first[i]=rank[secondSa[i]]; //在第二关键字排名为i的条件下第一关键字的排名 for(int i=0; i<up; i++)c[i]=0;//这里上界不是n而是up for(int i=0; i<n; i++)c[first[i]]++; for(int i=1; i<up; i++)c[i]+=c[i-1]; for(int i=n-1; i>-1; i--)sa[--c[first[i]]]=secondSa[i]; //从大到小(第二关键字已经是有序) int *tmp,i; for(tmp=rank,rank=secondSa,secondSa=tmp,rank[sa[0]]=0,i=p=1; i<n; i++) {//rank[]其实是根据它自己进行计算 rank[sa[i]]=cmp(secondSa,sa[i],sa[i-1],halfLen)?p-1:p++; //最后一个字符的用处sa[i]+halLen或sa[i-1]+halfLen会越界!! //重新筛出排名相等的下标 //若第一,二关键字都不同则排名应该+1 } } } void calHeight() { //根据性质h[i]>=h[i-1]-1,height[rank[i]]=h[i]依次计算出h[0],h[1],……h[n-1] int preRankLable,preLen=0; //preRankLable表示前一名的下标 //preLen表示下标为cur-1的长度 for(int cur=0; cur<n; cur++) { if(rank[cur]) { for(preLen?--preLen:0,preRankLable=sa[rank[cur]-1]; r[cur+preLen]==r[preRankLable+preLen]; preLen++); height[rank[cur]]=preLen; } else height[0]=preLen=0; } } } suffixArray; int main() { // freopen("data.in","r",stdin); suffixArray.init(); string master,pattern; while( cin>>master>>pattern) { int loc=master.size(); suffixArray.input(master+SuffixArray::NONE+pattern); suffixArray.calSA(); suffixArray.calHeight(); int maxi=0,cur,pre=suffixArray.sa[0]; for(int i=1; i<suffixArray.n; i++) { cur=suffixArray.sa[i]; if((loc-cur)*(loc-pre)<0)maxi=max(maxi,suffixArray.height[i]); pre=cur; } cout<<maxi<<endl; } return 0; }
int maxi=0,cur,pre=suffixArray.sa[0]; for(int i=1; i<suffixArray.n; i++) { cur=suffixArray.sa[i]; if((loc-cur)*(loc-pre)<0)maxi=max(maxi,suffixArray.height[i]); pre=cur; } cout<<maxi<<endl;
int maxi=0; for(int i=1; i<suffixArray.n; i++) { if(maxi<suffixArray.height[i]) { if(suffixArray.sa[i]>=master.length()+1||suffixArray.sa[i-1]>=master.length()+1) maxi=suffixArray.height[i]; } } cout<<maxi<<endl;