后缀数组复习小记

14 篇文章 3 订阅
7 篇文章 0 订阅
本文是关于后缀数组的复习笔记,介绍了DA算法的构造过程,包括数组的维护和离散化优化,以及如何求height数组。还提到了常见的解决思路,如单调栈处理height和使用数据结构进行区间问题的维护。
摘要由CSDN通过智能技术生成

前言

复习小记差不多是写给自己看的,步骤都比较简略,主要总结要点。初学者的话还是去看罗穗骞的论文吧。
这个东西我初二就会了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+l1 j+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、付费专栏及课程。

余额充值