后缀数组构造

  读了罗穗的论文,终于知道后缀数组怎么构造了,还反复打了五遍,打得很痛苦才最终理解。

  终于体会到XY的痛苦了。实在是一篇OI生涯中最难懂的代码orz看来两天。一下是经过稍微加长的稍微易理解的代码(其实差不多好吧)。

  具体注释看 网址

  

 1 #include<cstdio>
 2 #include<string.h>
 3 #include<iostream>
 4 using namespace std;
 5
 6 struct suffix_array
 7 {
 8     const long N;
 9     long *sa,*sa2,*hgt,*rk,n;
10     char *str;
11     suffix_array(long maxn=10000):N(maxn)
12     {
13         str=new char[N];
14         sa=new long[N],sa2=new long[N],hgt=new long[N],rk=new long[N];
15     }
16
17     bool same(long *rank,long id1,long id2,long len)
18     {
19         return rank[id1]==rank[id2]&&rank[id1+len]==rank[id2+len];
20     }
21     void make_sa()
22     {
23         long *cnt,m,i,len,p;
24         cnt=new long[N+26];
25         memset(cnt,0,sizeof(long)*(N+26));
26         for (i=0;i<n;i++){
27             cnt[rk[i]=str[i]-‘a‘]++;
28             m=(rk[i]>m)?rk[i]:m;
29         }
30         m++;
31         for (i=1;i<m;i++)cnt[i]+=cnt[i-1];
32         for (i=0;i<n;i++)sa[--cnt[rk[i]]]=i;
33
34         for (len=1;len<n;len*=2){
35             for (i=n-len,p=0;i<n;i++)sa2[p++]=i;
36             for (i=0;i<n;i++)
37                 if (sa[i]>=len)sa2[p++]=sa[i]-len;
38
39             memset(cnt,0,sizeof(long)*m);
40             for (i=0;i<n;i++)cnt[rk[i]]++;
41             for (i=1;i<m;i++)cnt[i]+=cnt[i-1];
42             for (i=0;i<n;i++)sa[--cnt[rk[sa2[i]]]]=sa2[i];
43
44             swap(rk,sa2);
45             rk[sa[0]]=0;
46             for (i=1;i<n;i++){
47                 rk[sa[i]]=rk[sa[i-1]];
48                 if (!same(sa2,i,i-1,len))rk[sa[i]]++;
49             }
50             m=rk[sa[n-1]]+1;
51             if (m==n)break;
52         }
53     }
54
55     void make_hgt()
56     {
57         long i,j,lcp;
58         for (i=0,lcp=0;i<n-1;i++){
59             if (lcp>0)lcp--;
60             j=sa[rk[i]-1];
61             while (str[j+lcp]==str[i+lcp])lcp++;
62             hgt[rk[i]]=lcp;
63         }
64     }
65
66     void Build(char *s)
67     {
68         n=strlen(s);
69         memcpy(str,s,sizeof(n));
70         make_sa();
71         make_hgt();
72     }
73 };
74
75 int main()
76 {
77     suffix_array SA(10000);
78     return 0;
79 }

  后缀数组和后缀自动机一样,还是很有用的。不会打SA或SAM遇到字符串必定会挂。

时间: 2024-12-25 05:50:15

后缀数组构造的相关文章

利用后缀数组构造后缀树

由于蒟蒻azui前段时间忙着准备省选,并在省选中闷声滚大粗,博客停更了好久.. 省选过后整个人各种颓,整天玩玩泥巴什么的... 前段时间学后缀数组的时候上网查相关资料,看到说后缀数组和后缀树是可以相互转化的,并且uoj上有大量通过后缀自动机建出后缀树然后dfs遍历获得后缀数组的模板,但是通过后缀数组来建后缀树的资料确实稀缺. 也许大牛们都觉得这xjbYY一下就可以写了,所以网上没找到对应的代码,那么我来补个坑吧.大牛勿喷.. 先谈谈我的理解吧.. 讲道理后缀数组和后缀树应该是完全等价的,但前两者

后缀数组(suffix array)

参考: Suffix array - Wiki 后缀数组(suffix array)详解 6.3   Suffix Arrays - 算法红宝书 Suffix Array 后缀数组 基本概念 应用:字符串处理.生物信息序列处理 后缀:学过英语的都知道什么叫后缀,就是从某个位置开始到字符串结尾的特殊子串,记住 Suffix(i)=S[i...len(S)-1],i就是后缀起始位置 后缀数组:就是将后缀排序好后放到一个一维数组里,SA[i]存放排名第i大的后缀首字符下标,并且保证 Suffix(SA

[算法]后缀数组

前言 这篇博客真难写,暂定待更 定义 后缀数组[SuffixArray]是一个一维数组,简称SA,它保存1到n的某个排列\(SA[1] ,SA[2],\dots,SA[n]\),并且保证\(Suffix(SA[i])<Suffix(SA[i+1])\),\(1 \leq i < n\) .也就是将s的n个后缀按字典序从小到大进行排序之后把排好序的后缀的编号顺次放入SA中. 我们先从后缀数组的入门题洛咕P3809讲起 名词解释 后缀[suffix]: ? 类似前缀,在字符串处理中意为对于一个初始

用倍增法构造后缀数组中的SA及RANK数组

感觉后缀数组很难学的说= = 不过总算是啃下来了 首先 我们需要理解一下倍增法构造的原理 设原串的长度为n 对于每个子串 我们将它用'\0'补成长度为2^k的串(2^k-1<n<=2^k) 比如串aba的子串就有 aba'\0'    ba'\0''\0'  a'\0''\0''\0' 每次操作我们可以排出所有长度为 2^x的子串的大小 比如串aba的排序过程 第一遍 a                   a             b 第二遍 a'\0'             ab  

后缀数组 DC3构造法 —— 详解

学习了后缀数组,顺便把DC3算法也看了一下,传说中可以O(n)复杂度求出文本串的height,先比较一下倍增算法和DC3算法好辣. DC3 倍增法 时间复杂度 O(n)(但是常数很大)   O(nlogn)(常数较小) 空间复杂度   O(n)    O(n) 编程复杂度    较高   较低 由于在时间复杂度上DC3的常数比较大,再加上编程复杂度比较高,所以在解决问题的时候并不是最优选择.但是学到了后缀数组还是补充一下的好点. DC3算法的实现: 1:先把文本串的后缀串分成两部分,第一部分是后

[bzoj1717][Usaco2006 Dec]Milk Patterns 产奶的模式 (hash构造后缀数组,二分答案)

以后似乎终于不用去学后缀数组的倍增搞法||DC3等blablaSXBK的方法了= = 定义(来自关于后缀数组的那篇国家集训队论文..) 后缀数组:后缀数组SA是一个一维数组,它保存1..n的某个排列SA[1],SA[2],……,SA[n],并且保证Suffix(SA[i])<Suffix(SA[i+1]),1≤i<n. 也就是将S的n个后缀从小到大进行排序之后把排好序的后缀的开头位置顺次放入SA中. height数组:定义height[i]=suffix(sa[i-1])和suffix(sa[

后缀数组(一堆干货)

其实就是将两篇论文里的东西整合在了一起,并且提供了一个比较好理解的板. 后缀数组 字符串:一个字符串S是将n个字符顺次排列形成的数组,n称为S的长度,表示为len(S).S的第i个字符表示为S[i]. 子串:字符串S的子串S[i…j],i<=j,表示从S串中从i到j这一段,也就是顺次排列S[i],S[i+1],……,S[j]形成的字符串. 后缀:后缀是指从某个位置i开始到整个字符串末尾结束的一个特殊子串.字符串S的从i开关的后缀表示为Suffix(S,i),也就是Suffix(S,i)=S[i…

POJ 2406 Power String 后缀数组

这题曾经用KMP做过,用KMP 做非常的简单,h函数自带的找循环节功能. 用后缀数组的话,首先枚举循环节长度k,然后比较LCP(suffix(k + 1), suffix(0)) 是否等于len - k, 如果相等显然k就是一个循环节. 得到LCP的话可以通过预处理出所有点和0的lcp就好了.另外倍增法构造后缀数组还有用RMQ来搞lcp nlogn是不行的,会超时,所以可以dc3走起了.. #include <cstdio> #include <cstring> #include

hdu 5008(2014 ACM/ICPC Asia Regional Xi&#39;an Online ) Boring String Problem(后缀数组&amp;二分)

Boring String Problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 219    Accepted Submission(s): 45 Problem Description In this problem, you are given a string s and q queries. For each que