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

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

设原串的长度为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. Eclipse Kepler安装WST Server Adapter后创建Server无Tomcat解决方法

    在Eclipse Kepler下安装完WST Server Adapter后,创建Server时发现没有Tomcat服务器的选项,这个问题解决起来很简单, 只需要安装一下JST Server Adap ...

  2. [CF804F]Fake bullions

    Solution: ​ 这题可以分为两个部分, ​ 一个部分为处理出每个点最大的金条数与最小的金条数,记为 \([Min_i, Max_i]\) ​ 第二部分为对于 \(n\) 个变量 \(x_i\i ...

  3. linux php 中session 多站点共享session问题

    linux php 中session默认file 假如修改为redis php.ini session.save_handler = "files"; session.save_p ...

  4. 没有找到mspdb80.dll,因此这个应用程序未能启动...问题解决

    这里主要针对使用link.exe进行SIG文件制作时,报错. 首先下载,mspdb80.dll:https://www.lanzous.com/i59dgfi 将dll文件移动到我的电脑(32位)C: ...

  5. JS中的reduce函数

    海纳百川,有容乃大 定义: reduce()方法接受一个函数作为累加器,数组中的每个值(从左向右)开始缩减,最终计算为一个值.对空数组是不会执行回调函数的. 案例: 计算数组总和: var num = ...

  6. 纯css实现星级评分效果

    效果 效果图如下,纯css实现超酷炫的星级评分动画效果 ​ 实现思路 5个类型为radio的input,label标签修改样式背景图为星星 label标签给每个星星鼠标停留时加注名字 点击星星有放大旋 ...

  7. vue 移动端列表筛选功能实现

    最近兴趣所致,打算使用vant搭建一个webapp,由于需要使用列表筛选,没有找到合适组件,于是写了一个简单的功能,权当记录. 效果如下:        HTML: <div class=&qu ...

  8. presentingViewController、presentedViewController区别

    解释两个属性:presentingViewController 和 presentedViewController A----(present)-----B----(present)-----C 1. ...

  9. 2018-2-13-win10-uwp-BadgeLogo-颜色

    title author date CreateTime categories win10 uwp BadgeLogo 颜色 lindexi 2018-2-13 17:23:3 +0800 2018- ...

  10. 转载:PhpExcel使用方法

    下面是总结的几个使用方法 include 'PHPExcel.php'; include 'PHPExcel/Writer/Excel2007.php'; //或者include 'PHPExcel/ ...