后缀数组概述

这里先不讲后缀数组的应用,表示目前我也不怎么会,先讲讲怎么求后缀数组。
后缀数组是什么?对于一个长度为 n n n的字符串,显然,它有n个后缀。我们要做的就是把这 n n n个后缀按字典序排序,根据后缀独特的性质,我们可以做到 O ( n l o g n ) O(nlogn) O(nlogn)的时间复杂度。
特别的,定义 r a n k rank rank数组, r a n k [ i ] rank[i] rank[i]表示第 i i i个下标开始的后缀的排名,定义 s a sa sa数组, s a [ i ] sa[i] sa[i]表示排名为 i i i的后缀起始位置。显然这 n n n个后缀的长度不相同,所以不会有两个排名相同的后缀。
举个例子:ababa
rank:3,5,2,4,1
sa:5,3,1,4,2

说说怎么排名

这里写图片描述

看懂这张图了吗?嗯,我们现在会排序了。???

我们使用倍增的思想,先对第一位进行排序,然后两位一起排,以上一次排名的前一段作为第一关键字,后一段作为第二关键字。然后四位一起排,以此类推。似乎看代码比较好懂,那我们上代码吧!

在这之前还是先说一句,这里需要基数排序什么的,基数排序计数排序傻傻分不清

   #include<iostream>  
   #include<cstdio>  
   #include<cstring>  
   using namespace std;  
   char s[1000005];//原字符串  
   int a[1000005];//字符串转数组  
   int rank[1000005],sa[1000005],tax[1000005],sec[1000005];/*rank[i]表示后缀i的排名;sa[i]表示排名为i的后缀位置;tax为基数排序的辅助数组;sec为排序的第二关键字,就是sa的魔改版,sec[i]表示排名为i的后缀向前数w个的位置*/  
   int len,m;//m为基数排序的最大值  
     
   void rsort()//基数排序  
   {  
       memset(tax,0,sizeof(tax));  
       for(int i=1;i<=len;i++) tax[rank[i]]++;  
       for(int i=1;i<=m;i++) tax[i]+=tax[i-1];  
       for(int i=len;i>=1;i--)  sa[tax[rank[sec[i]]]--]=sec[i];/*从后往前遍历,可以使第一关键字相同时,第二关键字小的排在前面*/  
   }  
     
   void suffx()  
   {  
       for(int i=1;i<=len;i++)//最开始只有第一关键字,初始化rank和sec  
         rank[i]=a[i],sec[i]=i;  
       m=127;  
       rsort();  
       for(int p=0,w=1;p<len;w+=w,m=p)//p是用来计数的,当没有两个相同排名的数时就结束排序  
       {  
           p=0;  
           for(int i=len-w+1;i<=len;i++) sec[++p]=i;//假如某一个位置向后数w个没有后缀了,它第二关键字一定是在前面  
           for(int i=1;i<=len;i++)//把向后数w个有后缀的按sa排  
             if(sa[i]>w)  
               sec[++p]=sa[i]-w;  
           rsort();  
           swap(rank,sec);rank[sa[1]]=1;p=1;//把rank根据sa赋值,sec中暂时存一下rank  
           for(int i=2;i<=len;i++)  
           {  
               if(sec[sa[i]]==sec[sa[i-1]]&&sec[sa[i]+w]==sec[sa[i-1]+w])//如果两个以2w排名相同,rank要赋成相同值。  
                 rank[sa[i]]=p;  
               else  
                 rank[sa[i]]=++p;  
           }  
       }  
   }  
     
   int main()  
   {  
       scanf("%s",s);  
       len=strlen(s);  
       for(int i=0;i<len;i++)  
         a[i+1]=s[i];  
       suffx();  
       for(int i=1;i<=len;i++)  
       {  
           printf("%d ",sa[i]);   
       }  
   } 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值