zoukankan      html  css  js  c++  java
  • 【学习笔记】后缀数组 SA

      人太蠢了还是不行,看个基数排序看出了脑震荡。

      一些规定:

        x位后缀:一个字符串去掉前x个字符串得出的字符串

    •   后缀排序

      后缀数组其实就是把一个字符串的所有后缀排序之后整出来的东西,例如

    aabbcca

      排序后

    aabbcca
    abbcca
    a
    bbcca
    bcca
    ca
    cca

      用于实现后缀排序的主要是倍增法,可以在O(nlogn)的时间复杂度内完成基数排序。而倍增算法也就像所有字符串算法的共性那样:利用已经完成计算的信息优化后一步的信息计算。

      就实现而言,我们步骤大体如下:

    1.   记录下所有后缀第一位的位置,作为它们的编号
    2.   先将所有后缀按照第一位的大小排序
    3.   把排好序的所有后缀与它编号+i(从1开始)的后缀“综合”一下,快速得出后缀们前2 ^ i次方位的排序。
    4.   把i * 2,重复第3、4步。

      那么,怎么把后缀“综合”一下呢?我们举个。

      假设我们已经把字符串acabaad按照第一位的大小排好了序

    acabaad
    abaad
    aad
    ad
    baad
    cabaad
    d
    

      设编号为i的字符串Si的排名为rki,那么可知,Si+1为Si的“一位后缀”。若Si与Sj第一位比较出的顺序相同,我们可以借rki+1与rkj+1对比出Si与Sj前两位的顺序,依次类推,若我们知道Si前len位的排序,我们可以借Si+len求出2 * len的排序。这样,逐位比较进行排序的次数就下降了许多次。

      考虑到在排序时,我们事实上只是综合了rki与rki+len进行排序,我们事实上有且仅有一些“两位数”rkirki+len要排序,可以选择优秀的基数排序把单次排序复杂度缩减至O(n)。

    •   基数排序

      这一部分乍一看很简单理解,事实上,要以正确而快速的复杂度实现又是另一码事了。

      思想相当简单,对于一个两位数,先将第二位进行桶排,再将桶排后的顺序用第一位桶排就可以保证两位数的排名了。但实现是一件相当有挑战性的事。

    •   height数组

    即lcp(sa[i - 1],sa[i]),height[i]也就是第i个字符串与在它排名前那个字符串的最长公共前缀。

    关于height[rk[i]] >= height[rk[i - 1]] - 1的证明:

      设位置为i - 1的后缀为s1,在它排名前的一个后缀为s2,设位置为i的后缀为s3,在它排名前的一个后缀为s4。若两字符串首字母不同,则height[rk[i - 1]] = 0,可得结果。

      若两字符串首字母相同,则两字符串的一位后缀的先后顺序同这两个字符串的先后顺序一样,也就是说s2的一位后缀在s3前,s2的一位后缀的排名<=s4。可知s4与s3的lcp要大于等于s4与s2的一位后缀的lcp。

      而s1的一位后缀与s2的一位后缀的lcp明显是height[rk[i - 1]] - 1,故结果成立。

    (证明思想剽窃自自为风月马前卒的博客) 

    口胡的证明,看不懂正常(我自己也看不懂)。

      有了这个,我们就可以从height[rk[i - 1]]快速推出height[rk[i]],复杂度为O(n)。

  • 相关阅读:
    python转换emoji字符串
    python位运算符详细介绍
    python制作动态排序图
    docker安装mysql
    yum安装centos-7版nginx
    pysimplegui模块实现倒计时UI框
    pysimplegui模块实现进度条
    python枚举的应用enum
    第0-0课
    SV -- Array 数组
  • 原文地址:https://www.cnblogs.com/Illusions/p/13885135.html
Copyright © 2011-2022 走看看