后缀数组(SA)and后缀自动机(SAM) 学习笔记&

一.后缀排序

后缀数组(𝑆𝑢𝑓𝑓𝑖𝑥 𝐴𝑟𝑟𝑎𝑦,𝑆𝐴)是一个处理字符串问题非常有用的数据结构。其基于将字符串的所有后缀按照字典序排序(称为后缀排序),维护后缀之间的最长公共前缀,将许多字符串问题转化为区间的问题求解

后缀数组定义: 表示字典序从小到大排名为𝑖的后缀的起始位置。

定义空字符的字典序小于任何其他字符。


#include<iostream>
#include<cstdio>
#include<cstring>
#define maxN 1000010
using namespace std;
char s[maxN];
int a[maxN],rk[maxN],sa[maxN],tp[maxN],tax[maxN],n,m=122;
//a是暂存数组,rk第i位的排名,sa是排名为i的位置,tp是第二关键字辅助用的,tax是桶数组;
inline void read(){
    scanf("%s",&s);
    n=strlen(s);
    for(int i=0;i<n;i++) a[i+1]=s[i];
}
inline void Rsort(){
    for(int i=0;i<=m;i++)tax[i]=0;
    for(int i=1;i<=n;i++)tax[rk[tp[i]]]++;
    for(int i=1;i<=m;i++)tax[i]+=tax[i-1];
    for(int i=n;i>=1;i--)sa[tax[rk[tp[i]]]--]=tp[i];
}
inline void Suffix(){
    for(int i=1;i<=n;i++)rk[i]=a[i],tp[i]=i;
    Rsort();
    for(int k=1;k<=n;k<<=1){
        int num=0;
        for(int i=n-k+1;i<=n;i++) tp[++num]=i;
        for(int i=1;i<=n;i++) if(sa[i]>k) tp[++num]=sa[i]-k;
        Rsort(),swap(rk,tp),num=rk[sa[1]]=1;
        for(int i=2;i<=n;i++)
        rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k])?num:++num;
        if(num==n)break;
        m=num;
    }
}
int main(){
    read(),Suffix();
    for(int i=1;i<=n;i++)printf("%d ",sa[i]);
}

update 2020.1.7

最长公共前缀

后缀数组在解决问题的时候几乎都要求一个最长公共前缀(𝐿𝑜𝑛𝑔𝑒𝑠𝑡𝐶𝑜𝑚𝑚𝑜𝑛𝑃𝑟𝑒𝑓𝑖𝑥,𝐿𝐶𝑃)

后缀数组将一个字符串所有的后缀处理好,那么后缀之间的前缀关系就非常重要。比如说经典的字符串匹配问题(𝐾𝑀𝑃可以𝑂(𝑛)解决),如果用后缀数组来做,我们就要把文本串和模式串接在一起(模式串接在后面),然后整个做后缀排序。匹配即找与模式串相等的子串,等价于在大串的所有后缀中寻找一个后缀,使得它与模式串(也是一个后缀)的𝐿𝐶𝑃长度等于模式串长度。而后缀排序后相同的前缀肯定排在一起。因此很多时候通过𝐿𝐶𝑃,字符串的问题能够转化为区间问题,因此线段树、莫队等数据结构就有了用武之地。

定义

定义𝐿𝐶𝑃(𝑖,𝑗):
表示后缀𝑖与后缀𝑗的𝐿𝐶𝑃长度。

定义ℎ𝑒𝑖𝑔ℎ𝑡:
数组表示两个排名相邻的后缀的𝐿𝐶𝑃。即ℎ𝑒𝑖𝑔ℎ𝑡𝑖=𝐿𝐶𝑃(𝑠𝑎𝑖−1,𝑠𝑎𝑖)

求Height数组

两个后缀的𝐿𝐶𝑃一定其排名那段ℎ𝑒𝑖𝑔ℎ𝑡中的最小值。这就是刚才所说的区间问题。因此只要高效地求出ℎ𝑒𝑖𝑔ℎ𝑡数组就能利用𝑆𝑇表来求得𝐿𝐶𝑃了。

我们不按排名顺序来求,而是按照后缀的位置从前到后来求ℎ𝑒𝑖𝑔ℎ𝑡

假设我们已经求得后缀𝑖−1与排在它前一个的后缀𝑘的ℎ𝑒𝑖𝑔ℎ𝑡,即已经求得ℎ𝑒𝑖𝑔ℎ𝑡[𝑟𝑛𝑘[i]−1]

接下来要考虑后缀𝑖和排在它前一个的后缀𝑝

后缀𝑖相对于后缀𝑖−1只少了第一个字符。而既然肯定的是后缀𝑘+1与后缀𝑖的𝐿𝐶𝑃为ℎ𝑒𝑖𝑔ℎ𝑡𝑟𝑛𝑘𝑖−1−1,那么𝐿𝐶𝑃(𝑝,𝑖)的长度至少会等于ℎ𝑒𝑖𝑔ℎ𝑡𝑟𝑛𝑘𝑖−1−1。因此有ℎ𝑒𝑖𝑔ℎ𝑡𝑟𝑛𝑘𝑖≥ℎ𝑒𝑖𝑔ℎ𝑡𝑟𝑛𝑘𝑖−1−1

而接下来多出的部分暴力匹配过去即可。因为我们的ℎ𝑒𝑖𝑔ℎ𝑡
近乎于单调递增(每次只减1),也就保证了求ℎ𝑒𝑖𝑔ℎ𝑡数组的复杂度是近似为𝑂(𝑛)的。


自为风月马前卒

DennyQi's Site


后缀自动机

posted @ 2020-01-05 21:42  白木偶君  阅读(469)  评论(0编辑  收藏  举报