感觉后缀数组很难学的说= = 不过总算是啃下来了

首先 我们需要理解一下倍增法构造的原理

设原串的长度为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           ba

第三遍 a'\0''\0''\0'   aba'\0'    ba'\0''\0'

理解这些后 我们可以先写一个 nlog^2n的快排实现的方法

这种方法比较好写 如果n<=10^5就放心地去用吧

//SA nlog^2n
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define rep(i,n) for(int i=1;i<=n;++i)
#define imax (x>y?x:y)
#define imax (x<y?x:y)
using namespace std;
const int N=;
struct node
{
int x,y,ma;
}tr[N];
char ch[N];
int r[N<<],sa[N];
int n;
bool cmp(node aa,node bb)
{
return aa.x<bb.x||(aa.x==bb.x&&aa.y<bb.y);
}
void getsa()
{
for(int i=;<<(i-)<n;++i)
{
rep(j,n)
{
tr[j].x=r[j];
tr[j].y=r[j+(<<i-)];
tr[j].ma=j;
}
sort(tr+,tr++n,cmp);
int cnt=;
rep(j,n)
r[tr[j].ma]=tr[j].x==tr[j-].x&&tr[j].y==tr[j-].y?cnt:++cnt;
}
rep(j,n)
sa[r[j]]=j;
}
int main()
{
scanf("%s",ch+);
n=strlen(ch+);
rep(i,n)
r[i]=ch[i];
getsa();
printf("RANK: ");
rep(i,n)
printf("%d ",r[i]);
printf("\nSA: ");
rep(i,n)
printf("%d ",sa[i]);
return ;
}

然而 考虑到rank数组的特殊性(一定<=n) 我们还可以使用基数排序把复杂度降到nlogn

这样就可以解决n<=10^6的问题啦

然而这个的确比较容易写错 并且需要先掌握基数排序的原理

基数排序从直观上是需要链表去做的 然而只用一个数组也同样可以很方便的实现

具体可以参考下代码

//SA nlogn(n=1需要特判下 这里懒得写了)
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define rep(i,n) for(int i=1;i<=n;++i)
#define imax (x>y?x:y)
#define imax (x<y?x:y)
using namespace std;
const int N=,S=;//通常字符都是在0-127之间的
char ch[N];
int sum[N],r[][N<<],sa[][N];
int n,t;
void getsa(int i)
//这里面的SA值并非最后的SA值 但保证对应rank值相等的一定相邻 从而方便比较大小
{
memset(sum,,sizeof(sum));
rep(j,n)
++sum[r[t][j+i]];
rep(j,n)
sum[j]+=sum[j-];
rep(j,n)
sa[][sum[r[t][j+i]]--]=j;
memset(sum,,sizeof(sum));
rep(j,n)
++sum[r[t][j]];
rep(j,n)
sum[j]+=sum[j-];
for(int j=n;j;--j)
//基数排序从第二次排序开始是一定要倒序找的(如果不懂的话自行搜索下基数排序)
sa[][sum[r[t][sa[][j]]]--]=sa[][j];
}
int main()
{
scanf("%s",ch+);
n=strlen(ch+);
rep(i,n)
sum[ch[i]]=;
for(int i=;i<S;++i)
sum[i]+=sum[i-];
rep(i,n)
r[][i]=sum[ch[i]];//函数外的sum用于求出初始排名
for(int i=;i<n;i<<=)
{
getsa(i);
t^=;
rep(j,n)
r[t][sa[][j]]=r[t^][sa[][j]]==r[t^][sa[][j-]]&&
r[t^][sa[][j]+i]==r[t^][sa[][j-]+i]?
r[t][sa[][j-]]:r[t][sa[][j-]]+;
if(r[t][sa[][n]]==n)break;//已经排好序了便可以提前退出
}
printf("RANK: ");
rep(i,n)
printf("%d ",r[t][i]);
printf("\nSA: ");
rep(i,n)
printf("%d ",sa[][i]);
return ;
}

用倍增法构造后缀数组中的SA及RANK数组的更多相关文章

  1. extract_by_one 根据二维数组中某字段来提取数组信息,查看有无重复信息

    public function tt(){ $param = array( array ( 'hykno' => '2222222-CB', 'tcdk_fid' => '458B6D70 ...

  2. MongoDB 学习笔记之 从数组中删除元素和指定数组位置

    从数组中删除元素: 从数组中删除单个元素: db.ArrayTest.updateOne({ "name" : "Bill"},{$pop: {"ad ...

  3. Javascript 获得数组中相同或不同的数组元素   

    Javascript 获得数组中相同或不同的数组元素 在Javascript中,偶尔会用到获取数组中相同或不同的元素值的情况,以下提供了获得数组中相同或不同的 元素函数供参考学习使用. // 数字类型 ...

  4. K:找寻数组中第n大的数组元素的三个算法

    相关介绍:  给定一个数组,找出该数组中第n大的元素的值.其中,1<=n<=length.例如,给定一个数组A={2,3,6,5,7,9,8,1,4},当n=1时,返回9.解决该问题的算法 ...

  5. C# 在数组中判断是否存在某个数组值

    (1) 第一种方法: ,,}; ); // 这里的1就是你要查找的值 ) // 不存在 else // 存在 (2) 第二种方法: string[] strArr = {"a",& ...

  6. 百度:在O(1)空间复杂度范围内对一个数组中前后连段有序数组进行归并排序

    一.题目理解 题目:数组al[0,mid-1]和al[mid,num-1]是各自有序的,对数组al[0,num-1]的两个子有序段进行merge,得到al[0,num-1]整体有序.要求空间复杂度为O ...

  7. 3.键盘输入10个数,放到数组中,(1)去除该数组中大于10的数 (2)将该数组中的数字写入到本地文件number.txt中

    package cn.it.text; import java.io.FileWriter; import java.io.IOException; import java.util.Scanner; ...

  8. 剑指Offer 35. 数组中的逆序对 (数组)

    题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000 ...

  9. 剑指Offer 37. 数字在排序数组中出现的次数 (数组)

    题目描述 统计一个数字在排序数组中出现的次数. 题目地址 https://www.nowcoder.com/practice/70610bf967994b22bb1c26f9ae901fa2?tpId ...

随机推荐

  1. Colourful Rectangle【扫描线】

    题目链接 很明显的可以发现是一个扫描线的问题,但是怎么处理区域呢,发现只有三种颜色,也就是最多也就是7种状态,那么我们可以进行一个状态压缩即可. 但是,在向上pushup的时候,存在我们要以子树的状态 ...

  2. fatal error C1047: The object or library file xxx was created with an older compiler than other objects

    之前编译Cocos2DX时遇到过一次,这次又遇到了,记下解决方法,以防再来第三次. 这个错误是说链接的库或者文件是老版本编译器生成的,与当前编译器不符,比如这次用的预编译库是2015的,而我当前使用的 ...

  3. MySQL基础(创建库,创建表,添加数据)

    CREATE DATABASE 数据库名; CREATE TABLE student2(sno VARCHAR(20) NOT NULL PRIMARY KEY COMMENT"学号&quo ...

  4. [已解决]报错: Error response from daemon: conflict

    报错内容: Error response from daemon: conflict: unable to delete f5b6ef70d79b (must be forced) - image i ...

  5. Codeforce 1175 D. Array Splitting

    新鲜热乎的题 Codeforce 1175 D. 题意:给出一个长度为$n$的序列$a$,你需要把它划分为$k$段,每一个元素都需要刚好在其中一段中.分好之后,要计算$\sum_{i=1}^{n} ( ...

  6. dp(最长公共子序列)

    A subsequence of a given sequence is the given sequence with some elements (possible none) left out. ...

  7. 10: Django + Uwsgi + Nginx 的生产环境部署

    1.1 一些重要概念 1.Web协议介绍 Web协议出现顺序: CGI -> FCGI -> WSGI -> uwsgi 1. CGI:  最早的协议 2. FCGI:  比CGI快 ...

  8. ReplaceAll 特殊字符处理

    用到Json与replaceAll Http拦截脚本中经常需要替换,replace虽然不需要处理特殊字符,但是不能匹配多个,ReplaceAll能够使用正则,不过需要处理的转移实在太多 比如,需要替换 ...

  9. 【JMeter5.0】Mac安装JDK和JMeter5

    之前讲了Windows下安装JDK和JMeter4.0的方法,其实不论操作系统是Windows.Mac OS.Linux等,JMeter所需要的基础环境配置都是类似的,本文介绍JMeter for M ...

  10. SqlServer 查看表注释

    SELECT DISTINCT d.name, f.value FROM syscolumns a LEFT JOIN systypes b ON a.xusertype= b.xusertype I ...