• [总结]后缀数组: 注释+模板


      

    以下模板单单注释了如何使用,算法详解可参考 罗穗骞《后缀数组——处理字符串的有力工具》

    算法注释:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
    using namespace std;
     
    const int maxn = 
     
     
    int s[maxn];
    int sa[maxn],c[maxn],t[maxn],t2[maxn];
     
    void build_sa(int m,int n) {
        int i,*x=t,*y=t2; 
        //提前一次基数排序 将sa[]求出
    	//基数排序后满足x递增 当x相同时 按照i递增的顺序 
        //sa[i]在每次k循环完之后都保留着目前排名第i的是谁 
    	for(i=0;i<m;i++) c[i]=0;
        for(i=0;i<n;i++) c[x[i]=s[i]]++;
        for(i=1;i<m;i++) c[i]+=c[i-1];
        for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
         
        for(int k=1;k<=n;k<<=1) {
        	//排序第二关键字 
        	//根据已经算出的sa[]算出y[]
    		//y[i]中保存着谁的第二关键字排名第i (i的第二关键字为i+k) 
            int p=0;
            for(i=n-k;i<n;i++) y[p++]=i;						//第二关键字为0的排在前面 
            for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;		//根据sa求出y 
            //排序第一关键字 
            //基数排序后满足x递增 当x相同时 按照y递增的顺序 
            for(i=0;i<m;i++) c[i]=0;
            for(i=0;i<n;i++) c[x[y[i]]]++;
            for(i=0;i<m;i++) c[i]+=c[i-1];
            for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
            //交换xy 并计算下一轮的x
    		//此时y中保存着原来的x  新的x是由排序产生的排名
            swap(x,y);
            p=1; x[sa[0]]=0;
            for(i=1;i<n;i++)
                x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;	
    		//若二元组的第一关键字与第二关键字相同的则名次相同
            if(p>=n) break;		//全部有序 即没有两个的名次是相等的 则停止倍增 
            m=p;	//m<-总名次数 
        }
    }
    
    int rank[maxn],height[maxn];
    void getHeight(int n) {
    	//H[i]=height[rank[i]]
    	//H[i]>=H[i-1]-1
        int i,j,k=0;
        for(i=0;i<=n;i++) rank[sa[i]]=i;
        for(i=0;i<n;i++) {
            if(k) k--;
            j=sa[rank[i]-1];
            while(s[j+k]==s[i+k]) k++;
            height[rank[i]]=k;
        }
    }
    

      

     使用注释:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
    using namespace std;
    
    const int maxn =             //长度范围 
    
    
    int s[maxn];                //字符串对应Ascii码 使用前可提前构造 
    int sa[maxn],c[maxn],t[maxn],t2[maxn];
    
    //m代表字符最大值 n代表字符串长
    //常常需要在字符串末尾加0以防止RE 令s[n]=0 调用build_sa(m,n+1)即可 
    void build_sa(int m,int n) {
        int i,*x=t,*y=t2;
        for(i=0;i<m;i++) c[i]=0;
        for(i=0;i<n;i++) c[x[i]=s[i]]++;
        for(i=1;i<m;i++) c[i]+=c[i-1];
        for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
        
        for(int k=1;k<=n;k<<=1) {
            int p=0;
            for(i=n-k;i<n;i++) y[p++]=i;
            for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
            
            for(i=0;i<m;i++) c[i]=0;
            for(i=0;i<n;i++) c[x[y[i]]]++;
            for(i=0;i<m;i++) c[i]+=c[i-1];
            for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
            
            swap(x,y);
            p=1; x[sa[0]]=0;
            for(i=1;i<n;i++) 
                x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
            if(p>=n) break;
            m=p;
        }
    }
    //n代表字符串长度
    //调用getHeight(n)即可 
    int rank[maxn],height[maxn];
    void getHeight(int n) {
        int i,j,k=0;
        for(i=0;i<=n;i++) rank[sa[i]]=i;  //[0,n]
        for(i=0;i<n;i++) {                  //不计算height[n] 即末尾0 
            if(k) k--;
            j=sa[rank[i]-1];
            while(s[j+k]==s[i+k]) k++;
            height[rank[i]]=k;
        }
    }
    
  • 相关阅读:
    真爱 vs. 种姓:新一代印度人的婚恋观
    美国司法部解禁guns打印技术
    特朗普访英,吃瓜群众却只想看《真爱至上》
    Semaphore(信号量)
    RLock(递归锁)
    用python编写九九乘法表
    php传值和传引用的区别
    post请求的header
    Content-type详解
    thinkphp5 学习笔记
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5003246.html
Copyright © 2020-2023  润新知