码迷,mamicode.com
首页 > 编程语言 > 详细

后缀数组

时间:2020-01-22 22:00:40      阅读:64      评论:0      收藏:0      [点我收藏+]

标签:排名   oid   ++   字符串   src   size   排序   sort   后缀数组   

将字符串每个后缀按照字典序排序

\(sa:\)表示排名为\(i\)的后缀的起始位置

\(rk:\)表示起始位置为\(i\)的后缀的排名

\(sa[rk[i]]=i,\ rk[sa[i]]=i\)

技术图片

通过倍增和基数排序来实现\(O(n\ log\ n)\)的排序

技术图片

基数排序时先排第一关键字,再在第一关键字相同下排第二关键字

第二关键字本身是有序的

\(num:\)表示当前排名的个数,也就是可以存在并列(当一二关键字都相等时),当\(num=n\)是就排好序了

\(tp:\)表示排名为\(num\)的后缀的位置,也是第二关键字排名为\(i\)的后缀的起始位置

\(rk[tp[i]]\)即为排名为\(i\)的第二关键字对应的第一关键字

\(b[rk[tp[i]]]\)即为当第一关键字相同时,第二关键字较大的该后缀的排名

所以\(sa[b[rk[tp[i]]]--]=tp[i]\)

\(rk\)\(tp\)数组大小应开成两倍

\(LCP\)最长公共前缀

\(ht:\)表示\(suff(sa[i])\)\(suff(sa[i-1])\)的最长公共前缀

\(h:\)表示\(ht[rk[i]]\)\(suff(i)\)和排序后它前一位的后缀的最长公共前缀

技术图片

\(h[i] \geqslant h[i-1]-1\)

所以\(suff(i)\)和它前一位后缀的最长公共前缀至少为\(h[i-1]-1\)

\(code:\)

void rsort()
{
    for(int i=0;i<=m;++i) b[i]=0;
    for(int i=1;i<=n;++i) b[rk[i]]++;
    for(int i=1;i<=m;++i) b[i]+=b[i-1];
    for(int i=n;i;--i) sa[b[rk[tp[i]]]--]=tp[i];
}
void SA()
{
    for(int i=1;i<=n;++i) rk[i]=str[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();
        memcpy(tp,rk,sizeof(rk));
        rk[sa[1]]=num=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;
    }
}
void height()
{
    int k=0;
    for(int i=1;i<=n;++i) rk[sa[i]]=i;
    for(int i=1;i<=n;++i)
    {
        if(rk[i]==1) continue;
        if(k) k--;
        int j=sa[rk[i]-1];
        while(str[i+k]==str[j+k]) k++;
        ht[rk[i]]=k;
    }
}

后缀数组

标签:排名   oid   ++   字符串   src   size   排序   sort   后缀数组   

原文地址:https://www.cnblogs.com/lhm-/p/12229570.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!