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

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

设原串的长度为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. Maven入门学习 (一)

    学习Java 的同学就一定会学习Maven, 那么Maven为什么会得到大量用户的使用呢?它是用来干什么的呢 ?接下来就来介绍 Q:Maven的作用? (1)Maven可以自动化构建项目,可以从清理. ...

  2. 《STL源码剖析》——第七、八章:仿函数与接配器

    第七章:仿函数  7.1.仿函数(函数对象)概观 STL仿函数的分类,若以操作数(operand)的个数划分,可分为一元和二元仿函数,若以功能划分,可分为算术运算(Arithmetic).关系运算(R ...

  3. JavaScript.convertArray

    function convertArray(nodeList){     var arr = []     if(Array.prototype.slice){         arr = [].sl ...

  4. CCNA 之 二 OSI七层模型

    OSI网际互联 OSI的概念 英文全称Open System Interconnect 开放系统互联参数模型,是由ISO国际标准化组织 定义的.它是个灵活的.稳健的和可互操作的模型,并不是协议,使用来 ...

  5. Java中的容器(集合)之HashMap源码解析

    1.HashMap源码解析(JDK8) 基础原理: 对比上一篇<Java中的容器(集合)之ArrayList源码解析>而言,本篇只解析HashMap常用的核心方法的源码. HashMap是 ...

  6. GeneXus笔记本—常用函数(下)

    这篇是常用函数的最后一节 当然 我这里聊的还不是全部的,需要各位朋友继续在工作中去深入才行啊 ,毕竟从入门到入土....┌(; ̄◇ ̄)┘ 1:Sleep 这个函数你们应该能猜到 ”To allow m ...

  7. JetbrainsCrack-4.2-release-enc.jar 激活补丁包

    http://wangshuo.jb51.net:81/201904/tools/JetbrainsCrack_jb51.rar ps:这里提供jetbrainscrack-2.10.jar.jetb ...

  8. python浮点数与整数间的转化

    舍弃小数部分 >>> math.trunc(12.533222) 12 >>> round(12.2544) 12 按给定小数位数四舍五入 >>> ...

  9. 第五节:从一条记录说起——InnoDB记录结构

    <MySQL 是怎样运行的:从根儿上理解 MySQL>第五节:从一条记录说起——InnoDB记录结构 准备工作 现在只知道客户端发送请求并等待服务器返回结果.    MySQL什么方式来访 ...

  10. Windows 搭建MongoDB分片集群(一)

    一.角色说明 要构建一个MongoDB分片集群,需要三个角色: shard server  即存储实际数据得分片,每个shard 可以是一个Mongod实例,也可以是一组mongod实例构成得Repl ...