后缀数组复习小记

本文是关于后缀数组的复习笔记,介绍了DA算法的构造过程,包括数组的维护和离散化优化,以及如何求height数组。还提到了常见的解决思路,如单调栈处理height和使用数据结构进行区间问题的维护。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

复习小记差不多是写给自己看的,步骤都比较简略,主要总结要点。初学者的话还是去看罗穗骞的论文吧。
这个东西我初二就会了23333333


DA算法构造

DA就是倍增算法。
每一层都有长度相等的一二关键字。
SA就是排名第i的后缀的开始位置,rank就是第i个后缀的排名。
数组x代表某后缀在上一层的rank,数组y代表按第二关键字的SA(位置是第一关键字开始处)。
Wv就是第二关键字第i的后缀的第一关键字(x[y[i]]),Ws就是Wv映射后做前缀和。
SA时倒着做来维护第二关键字的有序。
最后来处理这一轮的x,因为有些后缀在当前排序长度下会完全一样,所以用类似离散化的方法,比较函数cmp为:bool cmp(int *r,int i,int j,int l){return r[i]==r[j]&&r[i+l]==r[j+l];}
为了不特殊判断边界,我们只需将r(关键字数组,这里我们将x复制到y上,将y作为关键字r)至少开多一位就行了(如果满足r[i]==r[j],那至少i+l1j+l1是没有到边界的)。
这里有个小优化,当离散化后发现所有后缀都互不相同时,我们可以直接退出循环。这个优化实测效果好到飞起。
然后我们就扫一遍求rank即可。
这里是DA算法的代码(短小精悍):

void DA()
{
    int mx=0;
    for (int i=0;i<n;i++)mx=max(x[i]=Wv[i+1]=s[i]-'a'+1,mx);
    for (int i=0;i<=mx;i++)Ws[i]=0;
    for (int i=1;i<=n;i++)Ws[Wv[i]]++;
    for (int i=1;i<=mx;i++)Ws[i]+=Ws[i-1];
    for (int i=n;i>=1;i--)SA[Ws[Wv[i]]--]=i-1;
    /*初始处理这一段,如果字符集很大,就换用快排*/
    int l=1,p;
    while (l<=n)
    {
        p=0;
        for (int i=n-l;i<n;i++)y[++p]=i;
        for (int i=1;i<=n;i++)if(SA[i]>=l)y[++p]=SA[i]-l;
        mx=0;
        for (int i=1;i<=n;i++)mx=max(Wv[i]=x[y[i]],mx);
        for (int i=0;i<=mx;i++)Ws[i]=0;
        for (int i=1;i<=n;i++)Ws[Wv[i]]++;
        for (int i=1;i<=mx;i++)Ws[i]+=Ws[i-1];
        for (int i=n;i>=1;i--)SA[Ws[Wv[i]]--]=y[i];
        for (int i=0;i<=n;i++)y[i]=x[i],x[i]=0;
        p=1;
        x[SA[1]]=1;
        for (int i=2;i<=n;i++)x[SA[i]]=cmp(SA[i-1],SA[i],l)?p:++p;
        if (p==n)break;//小优化
        l<<=1;
    }
    for (int i=1;i<=n;i++)rank[SA[i]]=i;
}

至于DC3,我不会,一般出题人不会丧心病狂卡你的构造,如果实在不行,那估计正解就是SAM(后缀自动机)了。


height数组

我们定义height表示length(LCP(suffix(SA[i]),suffix(SA[i1])))
然后令rank[i]rank[j],那么length(LCP(suffix(i),suffix(j)))显然为

minjk=i+1height[k]

然后怎么线性求height呢?
我们令h[i]=height[rank[i]],可证h[i]h[i1]1(证明见论文)。
然后我们就可以按照h[1]h[2]……h[n]的顺序计算。这样时间复杂度显然为O(n)
height的代码如下:
void get_height()
{
    int k=0;
    for (int i=0;i<n;i++)
    {
        k=k?k-1:0;
        if (rank[i]==1)
            continue;
        int j=SA[rank[i]-1];
        while (i+k<n&&j+k<n&&s[i+k]==s[j+k])
            k++;
        height[rank[i]]=k;
    }
}

常见思路

首先肯定要搞出以上全部东西,然后按排序后的顺序来分析。
通常是单调栈把height数组一顿乱搞。
当然还有按照排序后的顺序数据结构维护一些神奇的东西,比如搞棵主席树处理区间问题。
据说SA数组搞出来后可以快速建出后缀树,反正我还不会,会了之后再更吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值