后缀数组(基数排序)的具体分析

我看后缀数组,思想很容易懂,但是基数排序那边我确实理解了很久才理解,现在我写一份自己可以看懂的具体分析。

第一步,首先将所有的位置上的值装入数组中,并记录排名为i的数为sa[i],第i个数的排名为rank[i].

下面就要进行logn次的倍增操作,我们定义k为当前倍增长度

基数排序,痛苦ing

首先将每一对数的排名存到cur数组,cur[i][0]记录初始位置的排名,cur[i][1]为i+k位置上的排名

首先我们对第二关键字也就是cur[i][1]进行排名,用sa数组记录排名为i的在第几个

接下来,我们就对第一关键字进行排序,注意加入顺序为sa数组,这样可以保证,第一关键字一定时,排名小的一定在前面,从而保证了排序顺序,然后再按第一关键字进行加入。用链表处理会更容易懂一些

只能说白书上的代码真心看不懂,我对某位同学的程序加了一下注释,应该可以看懂。

 1 void Suffix_Array()
 2 {
 3     N++;
 4     rep(i, 0, N - 1) SA[i] = i;//初始排名
 5     sort(SA, SA + N, cmp);//根据位置排序
 6     rep(i, 1, N - 1) Rank[SA[i]] = (s[SA[i]] > s[SA[i - 1]]) ? i : Rank[SA[i - 1]];//记录每个点的排名
 7     for (int k = 1; ; k <<= 1)//枚举长度
 8     {
 9         rep(i, 0, N - 1) Cur[i][0] = Rank[i], Cur[i][1] = (i + k < N) ? Rank[i + k] : 0;//每一对点的排名
10         rep(i, 0, N) E[i].clear();
11         rep(i, 0, N - 1) E[Cur[i][1]].push_back(i);//将所有排名一样的点加入链表
12         for (int i = N, n = 0; i >= 0; --i)
13             for (int j = E[i].size() - 1; j >= 0; --j) SA[n++] = E[i][j];  //重新排名,大的在前,小的在后
14         rep(i, 0, N) E[i].clear();
15         rep(i, 0, N - 1) E[Cur[SA[i]][0]].push_back(SA[i]);//加入当前点的排名,保证排名小的在后面
16         for (int i = 0, n = 0; i <= N; ++i)
17             for (int j = E[i].size() - 1; j >= 0; --j) SA[n++] = E[i][j];//最终排名
18         //memset(Rank, 0, sizeof(Rank));
19         int Indep = 1;
20         rep(i, 1, N - 1)
21             if (Cur[SA[i]][0] == Cur[SA[i - 1]][0] && Cur[SA[i]][1] == Cur[SA[i - 1]][1])
22                 Rank[SA[i]] = Rank[SA[i - 1]], Indep = 0; else Rank[SA[i]] = i;//重新排名
23         if (Indep) break;
24     }
25 }

后缀数组(基数排序)的具体分析

时间: 2024-10-20 19:04:52

后缀数组(基数排序)的具体分析的相关文章

利用后缀数组(suffix array)求最长公共子串(longest common substring)

摘要:本文讨论了最长公共子串的的相关算法的时间复杂度,然后在后缀数组的基础上提出了一个时间复杂度为o(n^2*logn),空间复杂度为o(n)的算法.该算法虽然不及动态规划和后缀树算法的复杂度低,但其重要的优势在于可以编码简单,代码易于理解,适合快速实现. 首先,来说明一下,LCS通常指的是公共最长子序列(Longest Common Subsequence,名称来源参见<算法导论>原书第3版p223),而不是公共最长子串(也称为最长公共子串). 最长公共子串问题是在文本串.模式串中寻找共有的

后缀数组(一堆干货)

其实就是将两篇论文里的东西整合在了一起,并且提供了一个比较好理解的板. 后缀数组 字符串:一个字符串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…

后缀数组

后缀数组是处理字符串的一种常用算法,是后缀树的一种精巧的替代品,它比后缀树更容易编程实现,且效率和后缀树相当. 后缀数组定义 子串: 字符串S的子串r[i, j](i <= j),表示r串中从i到j这一段形成的字符串. 后缀: 后缀是指从某个位置i开始到整个串末尾结束的一个特殊子串.字符串r的从第i个字符开始的后缀表示为 Suffix(i), Suffix(i) = r[i, len-1].一个串S长度为len(S),则它有len(S)个后缀 Suffix(0), Suffix(1).... S

后缀数组 &amp; 题目

后缀数组被称为字符串处理神器,要解决字符串问题,一定要掌握它.(我这里的下标全部都是从1开始) 首先后缀数组要处理出两个数组,一个是sa[],sa[i]表示排名第i为的后缀的起始位置是什么,rank[i]表示第i个字符为起始点的后缀,它的排名是什么.可以知道sa[rank[i]] = i; rank[sa[i]] = i; 由于每个后缀各不相同,至起码长度不同,所以每个后缀是不可能相等的. 解除一个值,就能在O(n)时间内得到另外一个. 定义:suffix(i)表示从[i, lenstr]这个后

[知识点]后缀数组

// 本文部分内容参照刘汝佳<算法竞赛入门经典训练指南>,特此说明. 1.前言 趁着这几天上午,把后缀数组大致看完了.这个东西本身的概念可能没太大理解问题,但是它所延伸出来的知识很复杂,很多,还有它的两个兄弟——后缀树,后缀自动机,编起来都不是盖的. 2.概念 前面曾经提到过Aho-Corasick自动机(http://www.cnblogs.com/jinkun113/p/4682853.html),讲得有点简略...它用以解决多模板匹配问题.但是前提是事先知道所有的模板,在实际应用中,我们

hiho一下123周 后缀数组四&#183;重复旋律

后缀数组四·重复旋律4 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成的数列.小Hi在练习过很多曲子以后发现很多作品中的旋律有重复的部分. 我们把一段旋律称为(k,l)-重复的,如果它满足由一个长度为l的字符串重复了k次组成. 如旋律abaabaabaaba是(4,3)重复的,因为它由aba重复4次组成. 小Hi想知道一部作品中k最大的(k,l)-重复旋律. 解题方法提示 输入 一

后缀数组模板(理解)

字符串的处理真可谓是博大精深,后缀数组这种数据结构我花了两天时间才明白了其构造的过程.主要是代码不好理解. 数据结构: 1.sa数组,就是后缀数组,按照字典序排列,其意义为:sa[i]=k,排第i名的子串是从k位开始的. 2.rank名次数组,其意义为:rank[i]=k,以i为起点的子串排名为k. 很容易看出来两者可以相互转化. 求这两个数组的过程是基于基数排序,计数排序的方法. 下面是一个大牛的注释版.其中我在补充点: 1.对于求y[]这个数组,因为已经知道上次长为j的子串比较结果,那么这次

hiho一下120周 后缀数组一&#183;重复旋律

后缀数组一·重复旋律 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成的数列. 小Hi在练习过很多曲子以后发现很多作品自身包含一样的旋律.旋律是一段连续的数列,相似的旋律在原数列可重叠.比如在1 2 3 2 3 2 1 中 2 3 2 出现了两次. 小Hi想知道一段旋律中出现次数至少为K次的旋律最长是多少? 解题方法提示 输入 第一行两个整数 N和K.1≤N≤20000 1≤K≤N

【后缀数组】

1 #include <iostream> 2 #include <cstring> 3 #include <cstddef> 4 #include <cstdio> 5 #include <string> 6 #include <algorithm> 7 const int maxn = 100001; 8 int wa[maxn],wb[maxn],wv[maxn],ws[maxn]; 9 int cmp(int *rank, i