zoukankan      html  css  js  c++  java
  • pku2774 求最长公共子串

    嘿嘿,用大牛的代码过的,我觉得,要理解这个好难呀,但要是用了模板计算后缀数组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;
    }
    
  • 相关阅读:
    .net core入门
    编码之Base64编码
    C++ 实现十大排序算法
    C++11 智能指针
    Object Pool 对象池的C++11使用(转)
    mac pro 1.5T内存是如何实现的
    Linux C/C++开发
    mac Chrome 快捷键
    C++11多线程
    Java项目压力测试(待补)
  • 原文地址:https://www.cnblogs.com/nanke/p/2049275.html
Copyright © 2011-2022 走看看