题目:后缀排序

什么是后缀数组?他主要包含两个数组:sa和rk。

其中sa[i]表示将字符串后缀排序后第i小的编号,rk[i]表示后缀i的排名。

显然sa[rk[i]]=i,rk[sa[i]]=i。

例如字符串aba,他的后缀aba,ba,a,排序后a,aab,ab,此时

| i | 1 | 2 | 3 |

| sa | 3 | 1 | 2 |

| rk | 2 | 3 | 1 |

观察上面给出的式子,发现都成立。

那如何求后缀数组呢,最简单的方法是直接排序,不要以为时间复杂度是O(nlogn),字符串比较还有一层O(n),所以总时间复杂度是O(n^2logn)的,显然不行。

既然快排不行,那用别的排序咯,我们发现字符个数很少,因此采用基数排序,但是朴素的基数排序是O(n^2)更慢了,因此这里使用倍增优化,每次枚举范围扩大一倍,为什么可行?

试想一下,如果对于基数排序,我们也可以通过压位,以10,100,甚至更多为一个单位,显然答案不会改变,只是效率的改变罢了,因此这里同理可以得到。

具体讲一下做法,设字符串s,先求出所有s[i]的排名,这就是最基础的对应关系,也就是以一个字符为基准的方法个数,接下来就是枚举长度了,每次求出二元组(k1[i],k2[i])表示排序的两个关键字,以k2[i]为关键字排序,然后再以k1[i]为关键字排,排序号后,求出所有数的排名,如果最大的编号为字符串长度,那么就说明已经完成了后缀排序,此时sa和rk中存储的就是最开始所说的内容。

时间复杂度O(nlogn),一个比较优秀的算法。

代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
const int N=1e6+5;
using namespace std;
int n,cnt[N],rk[N],psa[N],sa[N],k1[N],k2[N],m;
char s[N];
int main()
{
scanf("%s",s);
n=strlen(s);
m=max(n,300);
for(int i=0;i<n;i++)
cnt[(int)s[i]]++;
for(int i=1;i<m;i++)
cnt[i]+=cnt[i-1];
for(int i=0;i<n;i++)
rk[i]=cnt[(int)s[i]]-1;
for(int w=1;w<n;w<<=1)
{
for(int i=0;i<n;i++)
{
if(i+w>=n)
k2[i]=0;
else
k2[i]=rk[i+w];
k1[i]=rk[i];
}
for(int i=0;i<n;i++)
cnt[i]=0;
for(int i=0;i<n;i++)
cnt[k2[i]]++;
for(int i=1;i<m;i++)
cnt[i]+=cnt[i-1];
for(int i=n-1;i>=0;i--)
psa[--cnt[k2[i]]]=i;
for(int i=0;i<n;i++)
cnt[i]=0;
for(int i=0;i<n;i++)
cnt[k1[i]]++;
for(int i=1;i<m;i++)
cnt[i]+=cnt[i-1];
for(int i=n-1;i>=0;i--)
sa[--cnt[k1[psa[i]]]]=psa[i];
int tmp=1;
rk[sa[0]]=1;
for(int i=1;i<n;i++)
if(k1[sa[i]]==k1[sa[i-1]] && k2[sa[i]]==k2[sa[i-1]])
rk[sa[i]]=tmp;
else
rk[sa[i]]=++tmp;
if(tmp==n)
break;
}
for(int i=0;i<n;i++)
printf("%d ",sa[i]+1);
return 0;
}

2022春每日一题:Day 13的更多相关文章

  1. <每日一题>题目13:列表的简单问题

    ''' 分析: python赋值是通过指针来进行的. 很显然第一.三.四次调用都指向同一个列表,并未完成清空, 第二次调用只是指向了另一个列表,也未完成清空,很显然结果是累计的 结果: [0, 1] ...

  2. CISP/CISA 每日一题 13

    监控信息系统人员所提供服务的效率和效果的工具: 1.例外报告:识别所有没有成功完成的或出了故障的应用 2.作业重运行报告:大多数异常终止作业都会导致重起 3.操作员问题报告:记录计算机运行问题及解决方 ...

  3. 老男孩IT教育-每日一题汇总

    老男孩IT教育-每日一题汇总 第几天 第几周 日期 快速访问链接 第123天 第二十五周 2017年8月25日 出现Swap file….already exists以下错误如何解决? 第122天 2 ...

  4. PL/SQL Challenge 每日一题:2014-3-14 11gR2中带RELIES_ON子句的RESULT_CACHE函数

    PL/SQL Challenge 每日一题:2014-3-14 11gR2中带RELIES_ON子句的RESULT_CACHE函数 最先答对且答案未经编辑的puber将获得纪念章一枚(答案不可编辑但可 ...

  5. CISP/CISA 每日一题 五

    CISA 每日一题(答) 信息系统审计师要确认系统变更程序中的: 1.变更需求应有授权.优先排序及跟踪机制: 2.日常工作手册中,明确指出紧急变更程序: 3.变更控制程序应同时为用户及项目开发组认可: ...

  6. 「每日一题」有人上次在dy面试,面试官问我:vue数据绑定的实现原理。你说我该如何回答?

    关注「松宝写代码」,精选好文,每日一题 ​时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 来源:原创 一.前言 文章首发在「松宝写代码」 2020. ...

  7. [每日一题]面试官问:谈谈你对ES6的proxy的理解?

    [每日一题]面试官问:谈谈你对ES6的proxy的理解? 关注「松宝写代码」,精选好文,每日一题 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...

  8. 【JavaScript】Leetcode每日一题-二叉搜索树的范围和

    [JavaScript]Leetcode每日一题-二叉搜索树的范围和 [题目描述] 给定二叉搜索树的根结点 root,返回值位于范围 [low, high] 之间的所有结点的值的和. 示例1: 输入: ...

  9. 【python】Leetcode每日一题-寻找旋转排序数组中的最小元素

    [python]Leetcode每日一题-寻找旋转排序数组中的最小元素 [题目描述] 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组.例如,原数组nums ...

  10. 【JavaScript】【dp】Leetcode每日一题-解码方法

    [JavaScript]Leetcode每日一题-解码方法 [题目描述] 一条包含字母 A-Z 的消息通过以下映射进行了 编码 : 'A' -> 1 'B' -> 2 ... 'Z' -& ...

随机推荐

  1. MySQL插入重复数据

    MySQL中批量insert into时防止更新插入重复数据去重的方法,主要是讲到了ignore,Replace,ON DUPLICATE KEY UPDATE三种方法 方案一:使用ignore关键字 ...

  2. Homework6

    1.问:阅读和了解什么是形式化方法? 答:形式化方法在逻辑科学中是指分析.研究思维形式结构的方法.是把各种具有不同内容的思维形式(主要是命题和推理)加以比较,找出各个部分相互联结的方式,抽取出共同的形 ...

  3. git 密码修改

    当由于修改了Git 的密码导致 pull 等操作报错时,比如报以下错误: fatal: Authentication failed for 'http://xxxxxxxxxxxxxxxxxx.git ...

  4. Linux零拷贝原理

    Linux零拷贝原理 前言 磁盘可以说是计算机系统最慢的硬件之一,读写速度相差内存 10 倍以上,所以针对优化磁盘的技术非常的多,比如零拷贝.直接 I/O.异步 I/O 等等,这些优化的目的就是为了提 ...

  5. Nginx几种负载均衡方式介绍

    Nginx几种负载均衡方式介绍 前言 负载均衡就是Nginx将请求分摊到不同的服务器中,保证服务的可用性,缓解服务压力,保证服务的响应速度,即使某一个应用服务不可用,也可以保证业务的正常进行,并且方便 ...

  6. SpringBoot 配置文件使用详解

    一.创建一个SpringBoot项目 创建 SprintBoot 项目的 2 种方式: 在 https://start.spring.io/ 上创建一个 SpringBoot 项目,然后导入到 IDE ...

  7. k8s 如何关联pvc到特定的pv

    可以使用对 pv 打 label 的方式,具体如下: 创建 pv,指定 label $ cat nfs-pv2.yaml apiVersion: v1 kind: PersistentVolume # ...

  8. 使用ko安装的nexus想作为maven仓库使用

    默认安装的nexus并不能作为maven仓库使用,只能添加maven仓库来使用,具体可以查看该文档:使用nexus3配置maven私有仓库 https://www.cnblogs.com/sanduz ...

  9. MongoDB 的用户和角色权限

    副本和分片集群的安全设置参考这个:高级:https://files.cnblogs.com/files/sanduzxcvbnm/mongodb_advance.pdf 默认情况下,MongoDB实例 ...

  10. 使用FastDFS打造一款高可用的分布式文件系统

    FastDFS 介绍 参考: http://www.oschina.net/p/fastdfs FastDFS 是一个开源的分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文 ...