zoukankan      html  css  js  c++  java
  • 后缀数组入门学习(1):倍增算法基础

    满心欢喜来了后缀数组,但是发现自己很懵……

    后缀数组倍增算法的板子并不长,但理解起来相对很困难。

    后缀的含义自然不用说了……为了简洁,我们设后缀i为从第i位开始的后缀。

    需要这样几个数组:

    char s[],存字符串(废话),int sa[](本体),xx[](中转数组,存rank),yy[](中转数组,存编号),c[](基排用)

    然后我们需要预备知识:基数排序

    具体理论就不说了,可以参考百度百科;

    形象一点:找了一堆桶,把每个数/字符放在对应的桶里,然后按桶的编号挨个取出来,排好,就是基数排序。

    在代码实现上c数组就是我们的桶,c[i]表示“字符值小于等于i的字符个数”

    而对于字符值恰好等于i的那个字符,它的排名就是c[i](由于它是小于等于i的最大一个字符),然后我们把c[i]-=1即可

    代码长这样:

    1 memset(c,0,sizeof(c));
    2 for(int i=0;i<n;i++)c[x[i]=s[i]]++;//这里是一开始初始化赋值的地方
    3 for(int i=1;i<m;i++)c[i]+=c[i-1];
    4 for(int i=n-1;~i;i--)sa[--c[x[i]]]=i;

    接下来,我们就可以介绍本体代码了:

    首先,我们对每个字符排序,这样我们会得到每个字符的排名。可能有同学有疑问,按照基排的话,相同字母的排名就不同了怎么办?后面我们还会有去重的部分,所以我们中转数组这样不重复的打也没事。在这之后,我们给每个后缀的前两个字符排序(没有第二个字符的按照0处理,0最小,以后也是这样操作)。这相当于给一些二元组排序。利用我们刚刚第一次给字母排序的结果,很容易实现这次排序(我们在从第二次开始每次排序后面都会进行一次去重)。

    这之后,我们对每个后缀的前4个字符排序。由于对于后缀i和后缀j,给他们的前4个字符排序相当于“比较i和j的前两个字符”和“比较i+2和j+2的前两个字符”,而我们已经给前两个字符排好序,所以这样就可以利用前面排序的结果来操作。

    不断这样操作,当每个后缀的排名都不同时,就可以跳出了。

    代码见下:

     1 char s[N];
     2 int sa[N],rank[N],xx[N],yy[N],c[N],n;
     3 inline void get_sa(int m)//m为最大的字符值
     4 {
     5     int *x=xx,*y=yy;
     6     memset(c,0,sizeof(c));
     7     for(int i=0;i<n;i++)c[x[i]=s[i]]++;
     8     for(int i=1;i<m;i++)c[i]+=c[i-1];
     9     for(int i=n-1;~i;i--)sa[--c[x[i]]]=i;
    10     for(int k=1,p=0;k<=n;k<<=1,p=0)
    11     {
    12         for(int i=n-k;i<n;i++)y[p++]=i;
    13         for(int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
    14         memset(c,0,sizeof(c));
    15         for(int i=0;i<n;i++)c[x[y[i]]]++;
    16         for(int i=1;i<m;i++)c[i]+=c[i-1];
    17         for(int i=n-1;~i;i--)sa[--c[x[y[i]]]]=y[i];
    18         swap(x,y);
    19         p=1,x[sa[0]]=0;
    20         for(int i=1;i<n;i++)
    21             x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k])?p-1:p++;
    22         if(p>=n-1)return;m=p;
    23     }
    24 }
  • 相关阅读:
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    基于分布式锁解决定时任务重复问题
    基于Redis的Setnx实现分布式锁
    基于数据库悲观锁的分布式锁
    使用锁解决电商中的超卖
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7112103.html
Copyright © 2011-2022 走看看