ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

模板——后缀数组

2019-10-26 22:58:05  阅读:234  来源: 互联网

标签:关键字 后缀 离散 int 数组 排序 模板


后缀数组的详解参见此博客:https://www.cnblogs.com/victorique/p/8480093.html   这里主要理一下思路和注意点

 

后缀数组基本介绍:

后缀数组就是对一个字符串的$n$个后缀进行排序,但是考虑到每一个字符串都有一个长度,一位位比下来肯定炸飞,所以要优化。

先对于每一个字符进行离散化,每次按照倍增和前面的字符合并,然后合并后进行双关键字排序,再离散化,直至没有完全相同的值为止

总复杂度为$O(nlog(n))$

 

代码思路:第一次先预处理离散化,再塞进桶里。后面每次都是二维桶排序,再离散化合并,更新桶,每次用一个pair数组维护双关键字排序的数组信息

(之前没用pair,全用离散化数组num,结果第二关键字就被吃了。。)

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1020000;

int sa[N],rk[N],n;
char s[N];

pair<int,int> t[N];
int totb=0,tota=0;
int a[N],b[N],num[N];//now:桶的个数 
int pre[N],ord[N],cnt[N];//排名为i的id 
bool base_sort()
{
    int bl=1;
    for(int i=2;i<=n;i++) if(num[ord[i]]==num[ord[i-1]]) bl=0;
    if(bl) return 1;
    
    memset(cnt,0,sizeof(cnt));
    for(int i=0;i<=totb;i++) cnt[i]=b[i];
    for(int i=1;i<=totb;i++) cnt[i]+=cnt[i-1];
    for(int i=1;i<=n;i++) pre[cnt[t[i].second]--]=i;
    memset(cnt,0,sizeof(cnt));
    for(int i=0;i<=tota;i++) cnt[i]=a[i];
    for(int i=1;i<=tota;i++) cnt[i]+=cnt[i-1];//按第一关键字开桶 
    for(int i=n;i>=1;i--) ord[cnt[t[pre[i]].first]--]=pre[i];//按第二关键字从大到小进桶
    
    int now=0; tota=0,totb=0;
    for(int i=1;i<=n;i++)
    {
        if(t[ord[i]]!=t[ord[i-1]]) now++;
        num[ord[i]]=now;
    }
    return 0;
}

void merge(int B)
{
    //cout<<B<<endl;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(int i=1;i<=n;i++)
    {
        tota=max(tota,num[i]);
        totb=max(totb,num[i+(1<<B)]);
        t[i]=make_pair(num[i],num[i+(1<<B)]);
        a[num[i]]++; 
        b[num[i+(1<<B)]]++;
    }
}

pair<int,int> p[N];
void init()
{
    for(int i=1;i<=n;i++) 
    {
        p[i]=make_pair(s[i]-'A'+1,i);
    }
    sort(p+1,p+n+1);
    int now=0;
    for(int i=1;i<=n;i++) 
    {
        if(p[i].first!=p[i-1].first) now++;
        num[p[i].second]=now;
    }
    for(int i=1;i<=n;i++)
    {
        tota=max(tota,num[i]);
        t[i]=make_pair(num[i],0);
        a[num[i]]++; 
        b[0]++;
    }
}

int main() 
{
    scanf("%s",s+1);
    n=strlen(s+1);
    init();
    int B=0;
    while(!base_sort()) merge(B++);
    for(int i=1;i<=n;i++) printf("%d ",ord[i]);
    return 0;
}

 

一般不会只靠一个后缀数组,所以再增加一个辅助概念:LCP

 

后缀数组的具体应用:

 

标签:关键字,后缀,离散,int,数组,排序,模板
来源: https://www.cnblogs.com/Forever-666/p/11746105.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有