• 后缀数组


    用倍增思想求(sa_{k}[],rk_{k}[] -> sa_{2k}[],rk_{2k}[])
    用基数排序,排序二元组((rk[i],rk[i+k]))
    复杂度(O(Nlog{N}))

    #include<bits/stdc++.h>
    const int N=1000010;
    char s[N];
    int n,m,num;
    int sa[N],rk[N],bac[N],y[N],tmp[N];//sa[i]数组表示后缀排名为i的位置,rk[i]表示后缀[i..n]的排名
    int height[N];//height[i]表示rk为i的后缀与rk为i-1的后缀的LCP
    void getsa(){
        //rk[i]表示位置i的第一关键字(排名)
        //二元组(rk[i],rk[i+k])
        //初始化基数排序(单字符,其实是单元)
        for(int i=1;i<=n;i++)bac[rk[i]=s[i]]++;//bac[i]表示第一关键字小于i的个数
        for(int i=2;i<=m;i++)bac[i]+=bac[i-1];//故就先逐个统计,再求前缀和,相当于用桶计数
        for(int i=n;i>=1;i--)sa[bac[rk[i]]--]=i;//在第二关键字有序的情况下,对位置按照第一关键字的bac数组,逐个附排名 
        for(int k=1;k<=n;k<<=1){
            num=0;//排名的数量,初始化为单个字符的ASCLL码上限,m=ascll('z')=122
            //y[i]表示第二关键字排名为i的二元组的第一关键字位置(i)
            for(int i=n-k+1;i<=n;i++)y[++num]=i;//没有第二关键字的排名最靠前
            for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;//利用已有的sa_(k/2)数组,rk靠前的且有第一关键字的,将第一关键字位置sa_(k/2)[i]-k放入y
            //在上一轮中,rk_k数组已经求好了,倍增求解,
            //接下来利用基数排序,求出sa_k
            for(int i=1;i<=m;i++)bac[i]=0;
            for(int i=1;i<=n;i++)bac[rk[i]]++;//bac[i]表示第一关键字小于i的个数
            for(int i=2;i<=m;i++)bac[i]+=bac[i-1];//故就先逐个统计,再求前缀和,相当于用桶计数
            for(int i=n;i>=1;i--)sa[bac[rk[y[i]]]--]=y[i];//在第二关键字有序的情况下,对位置按照第一关键字的bac数组,逐个附排名 
            memcpy(tmp,rk,sizeof(tmp));//用tmp存一下rk_(k/2),在求rk_k时仍会用到
            //其实就是利用sa_k和rk_(k/2)数组求rk_k
            rk[sa[1]]=1;num=1;
            for(int i=2;i<=n;i++){
                if(tmp[sa[i]]==tmp[sa[i-1]]&&tmp[sa[i]+k]==tmp[sa[i-1]+k])rk[sa[i]]=num;
                else rk[sa[i]]=++num;
            }
            if(num==n)break;//已经有了n种排名
            m=num;//m表示排名的数量(在桶排中为值域)
        }
    }
    void geth(){
        //rk[i]=rk1,sa[rk1-1]=x;
        //rk[i-1]=rk2,as[rk2-1]=y;
        //height[rk1]=lcp(s[i..],s[x...]);
        //height[rk2]=lcp[s[i-1..],s[y...]);
        //lcp(s[i..],s[x..])>=lcp(s[i-1...],s[y...])
        for(int i=1;i<=n;i++){
            int x=sa[rk[i]-1];
            int k=std::max(0,height[rk[i-1]]-1);
            while(s[i+k]==s[x+k])++k;
            height[rk[i]]=k;
        }
    }
    int main(){
        scanf("%s",s+1);n=strlen(s+1);m=122;
        getsa();for(int i=1;i<=n;i++)printf("%d ",sa[i]);
        printf("
    ");
        geth();for(int i=2;i<=n;i++)printf("%d ",height[i]);
        return 0;
    }
    

    无注释版:

    #include<bits/stdc++.h>
    const int N=1000010;
    char s[N];
    int n,m,num;
    int sa[N],rk[N],bac[N],y[N],tmp[N];
    void getsa(){
        for(int i=1;i<=n;i++)bac[rk[i]=s[i]]++;
        for(int i=2;i<=m;i++)bac[i]+=bac[i-1];
        for(int i=n;i>=1;i--)sa[bac[rk[i]]--]=i;
        for(int k=1;k<=n;k<<=1){
            num=0;
            for(int i=n-k+1;i<=n;i++)y[++num]=i;
            for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;
            for(int i=1;i<=m;i++)bac[i]=0;
            for(int i=1;i<=n;i++)bac[rk[i]]++;
            for(int i=2;i<=m;i++)bac[i]+=bac[i-1];
            for(int i=n;i>=1;i--)sa[bac[rk[y[i]]]--]=y[i];
            memcpy(tmp,rk,sizeof(tmp));
            rk[sa[1]]=1;num=1;
            for(int i=2;i<=n;i++){
                if(tmp[sa[i]]==tmp[sa[i-1]]&&tmp[sa[i]+k]==tmp[sa[i-1]+k])rk[sa[i]]=num;
                else rk[sa[i]]=++num;
            }
            if(num==n)break;
            m=num;
        }
    }
    int main(){
        scanf("%s",s+1);n=strlen(s+1);m=122;
        getsa();for(int i=1;i<=n;i++)printf("%d ",sa[i]);
        return 0;
    }
    
  • 相关阅读:
    6-ESP8266 SDK开发基础入门篇--操作系统入门使用
    5-ESP8266 SDK开发基础入门篇--了解一下操作系统
    【java规则引擎】基本语法和相关属性介绍
    【eclipse】 怎么解决java.lang.NoClassDefFoundError错误
    【java规则引擎】java规则引擎搭建开发环境
    【4】JDK和CGLIB生成动态代理类的区别
    【java规则引擎】一个基于drools规则引擎实现的数学计算例子
    【3】SpringMVC的Controller
    设计模式之禅之代理模式
    【java规则引擎】规则引擎RuleBase中利用观察者模式
  • 原文地址:https://www.cnblogs.com/hangzz/p/13368161.html
Copyright © 2020-2023  润新知