用倍增法构造后缀数组中的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 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数组的更多相关文章
- extract_by_one 根据二维数组中某字段来提取数组信息,查看有无重复信息
public function tt(){ $param = array( array ( 'hykno' => '2222222-CB', 'tcdk_fid' => '458B6D70 ...
- MongoDB 学习笔记之 从数组中删除元素和指定数组位置
从数组中删除元素: 从数组中删除单个元素: db.ArrayTest.updateOne({ "name" : "Bill"},{$pop: {"ad ...
- Javascript 获得数组中相同或不同的数组元素
Javascript 获得数组中相同或不同的数组元素 在Javascript中,偶尔会用到获取数组中相同或不同的元素值的情况,以下提供了获得数组中相同或不同的 元素函数供参考学习使用. // 数字类型 ...
- K:找寻数组中第n大的数组元素的三个算法
相关介绍: 给定一个数组,找出该数组中第n大的元素的值.其中,1<=n<=length.例如,给定一个数组A={2,3,6,5,7,9,8,1,4},当n=1时,返回9.解决该问题的算法 ...
- C# 在数组中判断是否存在某个数组值
(1) 第一种方法: ,,}; ); // 这里的1就是你要查找的值 ) // 不存在 else // 存在 (2) 第二种方法: string[] strArr = {"a",& ...
- 百度:在O(1)空间复杂度范围内对一个数组中前后连段有序数组进行归并排序
一.题目理解 题目:数组al[0,mid-1]和al[mid,num-1]是各自有序的,对数组al[0,num-1]的两个子有序段进行merge,得到al[0,num-1]整体有序.要求空间复杂度为O ...
- 3.键盘输入10个数,放到数组中,(1)去除该数组中大于10的数 (2)将该数组中的数字写入到本地文件number.txt中
package cn.it.text; import java.io.FileWriter; import java.io.IOException; import java.util.Scanner; ...
- 剑指Offer 35. 数组中的逆序对 (数组)
题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000 ...
- 剑指Offer 37. 数字在排序数组中出现的次数 (数组)
题目描述 统计一个数字在排序数组中出现的次数. 题目地址 https://www.nowcoder.com/practice/70610bf967994b22bb1c26f9ae901fa2?tpId ...
随机推荐
- 基于Apache搭建HTTP HTTPS
参考资料 <openssl攻略>--第一章 <Apache服务器配置与使用工作笔记>-- 第六章 第十四章 https://juejin.im/post/5a31faf2518 ...
- knn算法手写字识别案例
import pandas as pd import numpy as np import matplotlib.pyplot as plt import os from sklearn.neighb ...
- java中高级开发知识准备要点
转载来源:https://www.cnblogs.com/JavaArchitect/p/10011253.html 在上周,我密集面试了若干位Java后端的候选人,工作经验在3到5年间.我的标准其实 ...
- SQL 查询中not in 与 not exists 的区别
1.in和exists in是把外表和内表作hash连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询,一直以来认为exists比in效率高的说法是不准确的.如果查询的两个表 ...
- Java 8实战之读书笔记一:内容简介
本书的主要内容如下: 如何使用Java 8新增的强大特性 如何编写能有效利用多核架构的程序 重构.测试和调试 怎样高效地应用函数式编程 目录: 第一部分 基础知识 第1 章 为什么要关心Jav ...
- mysql 8.0.15忘记密码重置方法
1.打开命令窗口cmd,输入命令:net stop mysql,停止MySQL服务, 2.开启跳过密码验证登录的MySQL服务 输入命令 mysqld --console --skip-grant-t ...
- CSS3中resize属性
说明: resize属性是指定一个元素是否可由用户调整大小的. 语法: resize:none | both | horizontal | vertical none:用户不可一调整元素的尺寸(默认值 ...
- 数组Array的方法调用
<script language="JavaScript" type="text/javascript"> var arr = ["11& ...
- windows server 2008R2 配置tomcat服务开机自启动
一.配置环境 操作系统:Windows server 2008 R2 软件包:jdk_1.7.rar 二.安装操作 1,右击解压jdk_1.7.rar:解压后双击运行jdk-7u79-windows- ...
- 一、表单和ajax中的post请求&&后台获取数据方法
一.表单和ajax中的post请求&&后台获取数据方法 最近要做后台数据接收,因为前台传来的数据太过于混乱,所以总结了一下前台数据post请求方法,顺便写了下相对应的后台接收方法. 前 ...