zoukankan      html  css  js  c++  java
  • 后缀数组模板及解释

    以前做过后缀数组,直接用模板,最近打算重新认真的学一遍。感觉学一个东西一定要弄懂了,不然到最后还是要重学。

    int wa[MAXN],wb[MAXN],wv[MAXN],Ws[MAXN];
    void da(int *r,int *sa,int n,int m){//n表示字符串长度 + 1,包括添加的那个0,m表示取值的范围
        //把单个字符进行基数排序
        int *x = wa,*y = wb;
        for(int i = 0; i < m; i++)Ws[i] = 0;
        for(int i = 0; i < n; i++)Ws[x[i]=r[i]]++;//在这里 x 数组保存的值相当于是 rank 值。下面的操作只是用 x 数组来比较字
                                                  //符的大小,所以没有必要求出当前真实的 rank 值。
        for(int i = 1; i < m; i++)Ws[i] += Ws[i-1];
        for(int i = n - 1; i >= 0; i--)sa[--Ws[x[i]]] = i;//注意i从n-1开始,因为要保证有相同字符时,靠前的更小
        int k,p;
        for(k = 1,p = 1; p < n; k <<= 1,m = p){//p表示第二关键字为0的个数。如果p==n说明所有后缀的关系已经确定了
                                               //k表示当前比较的字符串长度(倍增的长度?)
            p = 0;
            //下面2行代码表示对第二关键进行排序。
            //可以根据当前的sa[],进行排序
            //y[p]表示根据第二关键字排序后,其所对应的第一关键字。也就是论文图中第二关键字相连的第一关键字位置
            for(int i = n - k; i < n; i++)y[p++] = i;//k表示倍增的长度,那么n-k就是第二关键字为0的部分,及论文图中,没有第二关键
                                                     //字的那一部分,因为为0,所以在第二关键字的排序中会在前面。
                                                     //换句话说将 k−n 号字串的第二关键字排在最开头,因为这些标号的子串长度不足k
            for(int i = 0; i < n; i++)if(sa[i] >= k)y[p++] = sa[i] - k;//这里第二关键字的排序可以利用sa[],因为i从0开始,
                                                                       //sa[i]就是第i位大小,那么第二关键字也满足这个大小
                                                                       //sa[i] - k就是表示排在第i位的第二关键字对应的第一关键字位置
            //第二关键字基数排序完成后,y[]里存放的是按第二关键字排序对应第一关键字的下标
            for(int i = 0; i < m; i++)Ws[i] = 0;
            for(int i = 0; i < n; i++)Ws[x[y[i]]] ++;
            for(int i = 1; i < m; i++)Ws[i] += Ws[i-1];
            for(int i = n - 1; i >= 0; i--)sa[--Ws[x[y[i]]]] = y[i];//实际上就是先确定第二关健字排序中靠后的数,
                                                                    //这样最终排好的序第一关键字相同情况下,
                                                                    //第二关键字排序靠后的总排名也靠后。
            swap(x,y);
            p = 1;
            x[sa[0]] = 0;
            for(int i = 1; i < n; i++){
                x[sa[i]] = (y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k])?p-1:p++;//这里就是用x[]存储计算出的各字符串rank的值了,
                                                                                      //记得我们前面说过,计算sa[]值的时候如果字符串
                                                                                      //相同是默认前面的更小的,但这里计算rank的时候
                                                                                      //必须将相同的字符串看作有相同的rank,
                                                                                      //要不然p==n之后就不会再循环啦。
            }
    
        }
    }
    int rank[MAXN],height[MAXN];//height[]表示排名相邻的两个后缀的最长公共前缀。
    void calheight(int *r,int *sa,int n){
        int k = 0,j;
        for(int i = 1; i <= n; i++)rank[sa[i]] = i;
        for(int i = 0; i < n; height[rank[i++]] = k)
            for(k?k--:0,j = sa[rank[i]-1]; r[i+k] == r[j+k]; k++);
    }
    da(r,sa,len+1,128);
    calheight(r,sa,len);
  • 相关阅读:
    aspx页面,中文乱码解决方案
    使用JSP体验微信公众平台开发模式
    使用微信公众平台“编辑模式”的过程记录
    JAVA刷新网站IP访问量的技术探讨
    301. Remove Invalid Parentheses
    Dungeon Game
    刷题关键点总结-动态规划
    刷题关键点总结-单调栈、单调队列
    coin change
    常用vim命令
  • 原文地址:https://www.cnblogs.com/sweat123/p/5621628.html
Copyright © 2011-2022 走看看