后缀数组(讲解)

子串:从原串中选取连续的一段,即子串
空串也是子串
后缀:suf(k)为s(k…n)构成的子串
任何子串都是某个后缀的前缀
最长公共前缀 lcp(suf(i),suf(j))

问题:

将所有后缀suf(1),suf(2),suf(N)按照字典序从小到大排序

暴力sort N2 logN
二分+hash :
Nlog2N
cmp函数中二分suf(i)和suf(j)的lcp
return s[i+|lcp|] < s[j+|lcp|]
------- 以上为暴力做法
进入正文:
SA[1]排序第1的后缀的开始位置
Rank[i]=后缀suf(i)的排名
Rank[sa[l]] = l
sa[Rank[i]] = i
求sa然后得到rank
在这里插入图片描述
倍增
sub[i][k]:s从i开始长度为 2k的子串
sub[i][k] = s[i…i+(1<<k)-1 ],超过N的部分都视为’\0’(字典序最小符号)
rank[i][k]=sub[i][k]在长度2k的所有子串中的排名
sa[1][k] :在长度2k的所有子串中排名第1的子串的开始位置
step 1:先求sub[1][0],sub[2][0],…,sub[N][0]的字典排序
先求长度为1的子串,然后看字典序是多少
再求2,4,8,N,
当子串长度2k>=N时,子串排序就是后缀排序
利用rank[i…N][k],如何求出rank[1…N][k+1]
二分比较,
对于两个子串sub[i][k+1]与sub[j][k+1]比较
先比较rank[i][k]与rank[j] [ k ] (先比前半部分)
如果相等再比较rank[i+2k]与rank [ j+2k ] (比较后半部分)
相当于二元组(第一关键字–>rank[i][k],第二–>rank[i+2k][k])排序

在这里插入图片描述
注意rank[i][k]值域是不超过N的正整数,可以用基数排序(桶排序)
基础排序:先按second,再按照first
复杂度O(Nd) d是最大位数,此处d是2,(因为两个关键词)

在这里插入图片描述
写SA时用cnt数组实现
将a[i]数组(1~N)基数排序,结果存放在sa数组中
sa[1]:排名第1th的数在a中的下标

for(int i=1;i<=N;i++)cnt[a[i]++;//桶排
for(int i=1;i<=N;i++)cnt[i]+=cnt[i-1];//求前缀和
for(int i=N;i;i--)sa[cnt[a[i]]--]=i;//sa[cnt[a[i]]]=i,cnt[a[i]]--;

a=[2,1,2,4,2]
cnt=[1,3,0,1,0]
cnt=[1,4,4,5,5]
在这里插入图片描述
大致过程:
for k = 1 ~ logN
按rank[i+2k][k]基数排序(第二关键字)
按照rank[i][k]基数排序,(第一关键字)
得到sa[i][k+1]数组
由sa[i][k+1]求出rank[i][k+1]
动画链接
数据结构和算法动态可视化 (Chinese)
sa—>rank
rk[i]中有并列

for(p=0;i=1;i<=n;i++)
{if(oldrk[sa[i]]==oldrk[sa[i-1]]&&oldrk[sa[i]+k]==oldrk[sa[i-1]+k])rk[sa[i]]=p;else rk[sa[i]]=++p;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
oi-wiki

代码:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>using namespace std;const int N = 1000010;char s[N];
int n, sa[N], rk[N << 1], oldrk[N << 1], id[N], cnt[N];int main() {int i, m, p, w;scanf("%s", s + 1);n = strlen(s + 1);m = max(n, 300);for (i = 1; i <= n; ++i) ++cnt[rk[i] = s[i]];for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1];for (i = n; i >= 1; --i) sa[cnt[rk[i]]--] = i;//基数排序for (w = 1; w < n; w <<= 1) {//倍增memset(cnt, 0, sizeof(cnt));for (i = 1; i <= n; ++i) id[i] = sa[i];for (i = 1; i <= n; ++i) ++cnt[rk[id[i] + w]];for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1];for (i = n; i >= 1; --i) sa[cnt[rk[id[i] + w]]--] = id[i];//上面为第二部分基数排序,下面为第二部分基数排序memset(cnt, 0, sizeof(cnt));for (i = 1; i <= n; ++i) id[i] = sa[i];for (i = 1; i <= n; ++i) ++cnt[rk[id[i]]];for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1];for (i = n; i >= 1; --i) sa[cnt[rk[id[i]]]--] = id[i];memcpy(oldrk, rk, sizeof(rk));for (p = 0, i = 1; i <= n; ++i) {if (oldrk[sa[i]] == oldrk[sa[i - 1]] &&oldrk[sa[i] + w] == oldrk[sa[i - 1] + w]) {rk[sa[i]] = p;} else {rk[sa[i]] = ++p;}//由sa得到新的rank数组}}for (i = 1; i <= n; ++i) printf("%d ", sa[i]);return 0;
}

这个代码会超时,经过优化后:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>using namespace std;const int N = 1000010;char s[N];
int n, sa[N], rk[N], oldrk[N << 1], id[N], px[N], cnt[N];
// px[i] = rk[id[i]](用于排序的数组所以叫 px)bool cmp(int x, int y, int w) {return oldrk[x] == oldrk[y] && oldrk[x + w] == oldrk[y + w];
}int main() {int i, m = 300, p, w;scanf("%s", s + 1);n = strlen(s + 1);for (i = 1; i <= n; ++i) ++cnt[rk[i] = s[i]];for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1];for (i = n; i >= 1; --i) sa[cnt[rk[i]]--] = i;for (w = 1; w < n; w <<= 1, m = p) {  // m=p 就是优化计数排序值域for (p = 0, i = n; i > n - w; --i) id[++p] = i;for (i = 1; i <= n; ++i)if (sa[i] > w) id[++p] = sa[i] - w;memset(cnt, 0, sizeof(cnt));for (i = 1; i <= n; ++i) ++cnt[px[i] = rk[id[i]]];for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1];for (i = n; i >= 1; --i) sa[cnt[px[i]]--] = id[i];memcpy(oldrk, rk, sizeof(rk));for (p = 0, i = 1; i <= n; ++i)rk[sa[i]] = cmp(sa[i], sa[i - 1], w) ? p : ++p;}for (i = 1; i <= n; ++i) printf("%d ", sa[i]);return 0;
}

要求全文背诵
复杂度为O(n logn)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/319173.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2018 上海.NET职位围观报告

我一直说我是夏眠动物&#xff0c;如今已经11月份了&#xff0c;差不多也该活过来了&#xff0c;所以我决定写篇文章给各位.NET的支持者们和公司打打气&#xff0c;也算是为社区做点贡献吧。我最近主要干了两件事&#xff1a;让NPOI支持.NET Core&#xff0c;现已发布2.4版本。…

老张 .NetCore与Vue 框架学习

缘起作为一个.Net攻城狮已经4年有余了&#xff0c;一直不温不火&#xff0c;正好近来项目不是很忙&#xff0c;闲得无聊&#xff0c;搞一搞新技术&#xff0c;一方面是打发无聊的时间&#xff0c;一方面也是督促自己该学习辣&#xff01;身边的大神都转行的转行&#xff0c;加薪…

2018年10月28日宁波dotnet社区活动回顾及下次活动预告

离上次活动&#xff0c;有半年了&#xff0c;汗。之后尽量保证每月一次&#xff0c;以组织为主&#xff0c;多邀请嘉宾来分享。本次活动不足之处人手不足&#xff1a;由于活动组织事项受限于人手&#xff08;目前就我一个&#xff0c;这次活动前后我又应邀给大红鹰学院应届生介…

[JSOI2007]字符加密

题目描述 喜欢钻研问题的JS 同学&#xff0c;最近又迷上了对加密方法的思考。一天&#xff0c;他突然想出了一种他认为是终极的加密办法&#xff1a;把需要加密的信息排成一圈&#xff0c;显然&#xff0c;它们有很多种不同的读法。 例如‘JSOI07’&#xff0c;可以读作&…

BotSharp v0.2 发布, 支持微信智能回复

BotSharp v0.2 主要是针对微信的消息平台做整合&#xff0c;让.NET开发者可以轻松的搭建基于NLU自然语言理解的智能回复功能&#xff0c;BotSharp.Channel.Weixin模块负责和微信的公众号平台对接&#xff0c;接收消息通知&#xff0c;并能消息产生智能回复&#xff0c;回复的内…

P2852 [USACO06DEC]Milk Patterns G

题目描述 Farmer John has noticed that the quality of milk given by his cows varies from day to day. On further investigation, he discovered that although he can’t predict the quality of milk from one day to the next, there are some regular patterns in th…

c# 弹性和瞬态故障处理库Polly 学习

关于PollyPolly是一个基于.NET的弹性及瞬态故障处理库,允许开发人员以顺畅及线程安全的方式执行重试(Retry)、断路(Circuit Breaker)、超时(Timeout)、隔离(Bulkhead Isolation)和回退策略(Fallback ).Polly适用于 .NET 4.0, .NET 4.5 和.NET Standard 1.1。以上是官方文档对po…

TechEmpower最新一轮的性能测试出炉,ASP.NET Core依旧表现不俗

TechEmpower在10月30发布最新一轮&#xff08;Round 17&#xff09;针对“Web Framework Benchmarks”的性能测试报告&#xff0c;ASP.NET Core依旧表现不俗&#xff0c;在一些指标上甚至是碾压其他主流Web框架。为此我们做了一个简单的统计&#xff0c;看看ASP.NET Core和其他…

国内开源社区巨作AspectCore-Framework入门

前些天和张队(善友),lemon(浩洋),斌哥(项斌)等MVP大咖一块儿吃饭,大家聊到了lemon名下的AOP这个项目,我这小白听得一脸懵逼,后面回来做了一下功课,查了下资料,在lemon的Github上把这个项目学习了一下,收获颇丰,让我这个没有接触过AOP的Coder叹为观止,陷入了对lemon的深深崇拜,在…

HarmonyOs4.0基础(一)

目录 一、HarmonyOs系统定义 1.1系统的技术特性(三大特征) 1.1.1、硬件互助、资源共享 1.1.2、一次开发、多端部署(面向开发者) 1.1.3、统一OS&#xff0c;弹性部署(支持多种API&#xff1a;ArkTs、JS、C/C、Java) 1.2、系统的技术架构 二、Harmony OS项目搭建 2.1、(D…

swagger文档转换为WebApiClient声明式代码

1 swagger简介Swagger是一个规范且完整的框架&#xff0c;提供描述、生产、消费和可视化RESTful Web Service。其核心是使用json来规范描述RESTful接口&#xff0c;另外有提供UI来查看接口说明&#xff0c;并有一套生成不同语言的客户端调用代码生成器。1.1 对Api提供者自顶向下…

Musical Theme pku1743 (后缀数组)

Musical Theme(后缀数组) 题意&#xff1a; n个数&#xff0c;选取一段子序列&#xff0c;满足以下条件&#xff1a; 1.长度至少为5 2.在数列中其他位置出现过(允许转置) 3.与其他位置出现的不重叠 转置&#xff1a;将恒定的正或负值添加到子序列上 例如&#xff1a; n个数为…

KubeCon+CloudNativeCon首秀中国!

2018年11月13-15日&#xff0c;全球顶级的Kubernetes官方技术论坛KubeConCloudNativeCon将首次登陆中国&#xff0c;此次活动由云原生计算基金会&#xff08;CNCF&#xff09;主办&#xff0c;在上海跨国采购会展中心隆重举行。KubeCon CloudNativeConKubeConCloudNativeCon 是…

可持久化(一)

参考博客 可持久化数据结构&#xff1a;可以保留每一个历史版本&#xff0c;若所有版本都既可以访问又可以修改&#xff0c;成为完全可持久化&#xff08;可以回滚到某个历史版本&#xff09; 时间线&#xff1a; 可持久化线段树 可持久化下标线段树 题目&#xff1a; 模板…

ASP.NET Core中使用GraphQL - 第一章 Hello World

前言你是否已经厌倦了REST风格的API? 让我们来聊一下GraphQL。 GraphQL提供了一种声明式的方式从服务器拉取数据。你可以从GraphQL官网中了解到GraphQL的所有优点。在这一系列博客中&#xff0c;我将展示如何在ASP.NET Core中集成GraphQL, 并使用GraphQL作为你的API查询语言。…

11月7日邀您参加成都微软MVP圆桌之夜!

阅读文本大概需要 3.3 分钟。活动背景/规模成都一座来了就不想离开的城市&#xff0c;在此秋高气爽的日子里&#xff0c;我们迎来了成都微软最有价值专家&#xff08;MVP&#xff09;圆桌之夜。在过去的一年中&#xff0c;感谢各位MVP以杰出的专业知识在技术社区中解决了大量的…

Sangmado 公共基础类库

Sangmado&#xff08;发音 /sɔŋmɑːdu:/ ‘桑麻渡’&#xff09;涵盖了支撑 .NET/C# 项目开发的最基础的公共类库&#xff0c;为团队在不断的系统开发和演进过程中发现和积累的最公共的代码可复用单元。Sangmado 公共类库设计原则&#xff1a;独立性&#xff1a;不与任何业务…

【模板】卡特兰数

ACM模板 目录Catalan数证明卡特兰数应用Catalan数证明 1.卡特兰数递推式&#xff1a; an{1,n0∑i0n−1aian−1−i,n>0a_n\begin{cases} 1,n0\\\sum_{i0}^{n-1}a_ia_{n-1-i},n>0\end{cases} an​{1,n0∑i0n−1​ai​an−1−i​,n>0​ 2.卡特兰数组合数&#xff1a; an…

【活动(深圳)DevOps/.NET 微服务 秋季分享会】火热报名中!

无论身处开发还是运维岗位&#xff0c;您一定深刻地感受着业务需求带来的快速交付压力。在科技迅速发展的时代&#xff0c;传统行业积极开展数字化转型以在激烈竞争中脱颖而出&#xff0c;新兴行业不停歇地验证业务模式以找准市场定位&#xff1b;软件与行业变得密不可分&#…

微软正式发布Azure IoT Central

微软正式发布Azure IoT Central&#xff0c;这是一个面向物联网的软件即服务解决方案。借助该服务&#xff0c;微软旨在提供一种设计、开发、配置和管理IoT设备的低代码方式&#xff0c;同时提供开箱即用的安全性、可伸缩性以及与流程&应用程序集成。Azure IoT Central构建…