后缀数组-入门学习

利用后缀数组构造后缀树 由于蒟蒻azui前段时间忙着准备省选,并在省选中成功闷声滚大粗,博客停更了好久。。 阅读详情

后缀数组论文链接——处理字符串的有力工具_百度文库

后缀排序

Description

Tim正在自学《数据结构》,他刚刚学会如何比较两个字符串大小。书上是这么说的(和Pascal语言中的比较规则相同,学习过Pascal语言的同学可以跳过这段): 
比较两个不同字符串s1=’p1p2p3…pN’和s2=’q1q2q3…qM’的大小,设N<=M。 
若s1是s2的前缀,则s1<s2。否则设pi<>qi,且i最小;若pi<qi,则s1<s2,否则s1>s2。 
Tim想通过练习熟练运用这个规则,于是打算出许多字符串,并将它们从小到大排序。可是Tim非常懒,随机写出 K个很长的字符串实在是太麻烦了。不过聪明的他想到了一个好办法,他写了一个很长的字符串,自言自语说,“我只要把这个字符串的所有后缀从小到大排序就可以了”。 

Input

输入文件suffix.in中仅有一行,且是一个仅包含小写字母的字符串,长度K不超过10^5。 

Output

有K行,每行一个数字,第i行的数字Pi表示所有后缀中,第i小的是由原字符串第Pi个字符引导的后缀。 

Sample Input

 

mississippi

 

Sample Output

 

11 8 5 2 1 10 9 7 4 6 3

-----------------------------------------------------------------------------------------     分割线    ------------------------------------------------------------------------------------------------------------------------------

 code

#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<deque>
#include<stack>
#include<string>
#include<vector>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<time.h>

using namespace std;
typedef long long LL;
const int INF=2e9+1e8;
const int MOD=1e9+7;
const int MAXSIZE=1e6+5;
const double eps=0.0000000001;
void fre()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
}
#define memst(a,b) memset(a,b,sizeof(a))
#define fr(i,a,n) for(int i=a;i<n;i++)

int rankarr[MAXSIZE],wa[MAXSIZE],wb[MAXSIZE],height[MAXSIZE];
int wvarr[MAXSIZE],wsarr[MAXSIZE],SA[MAXSIZE];
char str[MAXSIZE];

int cmp(int *r,int a,int b,int l)
{
    return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(char *r,int *sa,int n,int m)
{
    int i,j,p,*x=wa,*y=wb,*t;
    for(i=0; i<m; i++) wsarr[i]=0;
    for(i=0; i<n; i++) wsarr[x[i]=r[i]]++;
    for(i=1; i<m; i++) wsarr[i]+=wsarr[i-1];
    for(i=n-1; i>=0; i--) sa[--wsarr[x[i]]]=i;
    for(j=1,p=1; p<n; j<<=1,m=p)
    {
        for(p=0,i=n-j; i<n; i++) y[p++]=i;
        for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
        for(i=0; i<n; i++) wvarr[i]=x[y[i]];
        for(i=0; i<m; i++) wsarr[i]=0;
        for(i=0; i<n; i++) wsarr[wvarr[i]]++;
        for(i=1; i<m; i++) wsarr[i]+=wsarr[i-1];
        for(i=n-1; i>=0; i--) sa[--wsarr[wvarr[i]]]=y[i];
        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
    return;
}
void calheight(char *r,int *sa,int n)
{
    int i,j,k=0;
    for(i=1; i<=n; i++) rankarr[sa[i]]=i;
    for(i=0; i<n; height[rankarr[i++]]=k)
        for(k?k--:0,j=sa[rankarr[i]-1]; r[i+k]==r[j+k]; k++);
    return;
}
int main()
{
    while(gets(str))
    {
        int n=strlen(str);
        str[n]=0;
        da(str,SA,n+1,128); //值得注意是 n+1
        calheight(str,SA,n);
        for(int i=1; i<=n; i++) printf("%d ",SA[i]);
        printf("\n");
        for(int i=0; i<n; i++) printf("%d ",rankarr[i]);
        printf("\n");
    }
    return 0;
}

这个字符串下标从 0~ n-1 

这个代码 rank[a]=b 表示suffix(a)的排名是 b   (注意:排名第一不是0,而是 1 ) 

 所以  rank[i]      0 <= i < n   

则      SA[i]         1<= i <= n

  排名是1到n   数组下标是0 到 n-1。



/***
DC3 算法:
相关数组开3倍大,SA,r 数组也是。
用法与DC3 一样。末尾添加0字符,插入的特殊字符串不能和末尾
字符相同。dc3 传参数长度需要 +1 。注意int 与 char

*/


#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int SA[MAXSIZE],Rank[MAXSIZE],height[MAXSIZE];
int wa[MAXSIZE],wb[MAXSIZE],wv[MAXSIZE],wss[MAXSIZE];
int c0(int *r,int a,int b)
{
    return r[a] == r[b] && r[a+1] == r[b+1] && r[a+2] == r[b+2];
}
int c12(int k,int *r,int a,int b)
{
    if(k == 2)
        return r[a] < r[b] || ( r[a] == r[b] && c12(1,r,a+1,b+1) );
    else return r[a] < r[b] || ( r[a] == r[b] && wv[a+1] < wv[b+1] );
}
void sort(int *r,int *a,int *b,int n,int m)
{
    int i;
    for(i = 0; i < n; i++)wv[i] = r[a[i]];
    for(i = 0; i < m; i++)wss[i] = 0;
    for(i = 0; i < n; i++)wss[wv[i]]++;
    for(i = 1; i < m; i++)wss[i] += wss[i-1];
    for(i = n-1; i >= 0; i--)
        b[--wss[wv[i]]] = a[i];
}
void dc3(int *r,int *sa,int n,int m)
{
    int i, j, *rn = r + n;
    int *san = sa + n, ta = 0, tb = (n+1)/3, tbc = 0, p;
    r[n] = r[n+1] = 0;
    for(i = 0; i < n; i++)if(i %3 != 0)wa[tbc++] = i;
    sort(r + 2, wa, wb, tbc, m);
    sort(r + 1, wb, wa, tbc, m);
    sort(r, wa, wb, tbc, m);
    for(p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++)
        rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p - 1 : p++;
    if(p < tbc)dc3(rn,san,tbc,p);
    else for(i = 0; i < tbc; i++)san[rn[i]] = i;
    for(i = 0; i < tbc; i++) if(san[i] < tb)wb[ta++] = san[i] * 3;
    if(n % 3 == 1)wb[ta++] = n - 1;
    sort(r, wb, wa, ta, m);
    for(i = 0; i < tbc; i++)wv[wb[i] = G(san[i])] = i;
    for(i = 0, j = 0, p = 0; i < ta && j < tbc; p++)
        sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];
    for(; i < ta; p++)sa[p] = wa[i++];
    for(; j < tbc; p++)sa[p] = wb[j++];
}


void calheight(int *r,int *sa,int n)
{
    int i,j,k=0;
    for(i=1; i<=n; i++) Rank[sa[i]]=i;
    for(i=0; i<n; height[Rank[i++]]=k)
        for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k]; k++);
    return;
}



VideoPose3D | 环境搭建 文章目录环境要求下载PyTorch基本步骤验证安装问题修复数据集设置Human3.6MCPN detections配置wget命令安装CPN评估环境测试问题测试报错 无法识别参数3 3 3 3卡在最后评估 主要参考:GitHub / facebookresearch / VideoPose3D 环境要求 Dependencies Make sure you have the followin... 阅读详情

相关推荐

RK3588开发板量产前必做:24小时DDR压力测试到底在测什么?(附ArmSoM-W3测试脚本解析)

本文深入解析RK3588开发板量产前的24小时DDR压力测试,揭示其核心价值与技术原理。通过memtester、stressapptest和变频测试的组合使用,全面验证DDR内存稳定性。特别介绍ArmSoM-W3测试脚本的创新设计,包括并行测试架构和异常熔断机制,为开发者提供可靠的量产测试方案。

weixin_30325487的博客 454

js实时录音 ws传输,传递后端asr识别,前端展示

3,点击开始,ws建联,sendData对获取的数据处理,分包处理每包1024.tmparr式处理过的音频。2,分为实时和非实时语音识别。(没有后端配合看不到效果展示)6,上传音频文件识别。(file音频文件做处理模拟蹦字效果)7,再次使用录音功能时,先清除file上传的内容。5,再次点击开始,刷新文本框。1,掉后端接口选择模式。4,点击关闭,链接断开。.........

tsqjxy的博客 2558

UG/NX二次开发实例流程样例(nx1980+vs2019)

以上就是基本操作了,下面进入界面开发流程,nx1980的界面开发操作,也需要在块UI界面编辑器中操作,很多教程都没有讲解这一点,尤其是如何进入块UI界面编辑器,那么我在这里详细说明一下步骤。》,这一篇文章我们将详细讲述,如何开发一个具体的功能——根据用户输入的数据,在特定的点上创建一个指定大小的立方体。可以将文件保存当桌面,笔者保存在桌面的create_block目录中了,如下图所示,可以发现生成了三个文件。4.在新建模型完成后,我们准备创建交互UI,按照下图所示的顺序,找到块UI界面编辑器,。

秋月的私语 1万+

2013-04-05 C++课件续

1.在函数调用结束后,形参被释放,实参保持原来的值。因此在函数执行后形参的改变主调函数的实参。 2.内置(内联)函数虽说增加了执行速度,但是会增大目标程序,因此一般只对规模小且执行频繁的函数使用内置,它不能包括控制语句如循环或switch函数。 3.在有默认参数值的函数中,如果有多个形参,指定默认值的形参一定要放在最右侧,否则出错。 4.在使用带有默认参数的函数时有两点要注意: • (1)

zhikdjr的专栏 535

【HSPiP应用指南】从理论到实践:如何利用汉森溶解度参数优化配方设计

本文深入解析了汉森溶解度参数(HSP)理论及其在配方设计中的核心价值,并详细介绍了如何利用HSPiP软件工具从理论走向实践。文章通过匹配溶解度参数、计算汉森距离(Ra),系统阐述了如何解决溶剂选择、颜料分散稳定性及扩散行为预测等关键问题,并结合界面气相色谱(IGC)等实验方法提升预测精度,旨在帮助配方师实现配方设计的可视化、可量化与高效优化。

weixin_29305313的博客 1646

KiCad自动布线实战:FreeRouting插件安装与使用指南

在PCB设计流程中,布线环节往往占据大量重复性工作,尤其对于中小型双面板,成百上千条飞线的手动连接既繁琐又易出错。自动布线技术通过算法在给定设计规则和元件布局的基础上自动规划走线路径,能显著提升布线效率。FreeRouting作为一款开源自动布线器,与KiCad通过DSN/SES标准中间格式无缝配合,让工程师将精力集中于关键信号和布局优化,而将常规网络交给工具处理。本文从自动布线的原理与边界出发,讲解了FreeRouting的安装、DSN导出、参数设置、自动布线及结果回传的完整流程,并结合实际案例展示了在S

weixin_32025789的博客 277

后缀数组学习与练习(入门向)

后缀数组学习与练习(入门向) Zbq 算法概述: 首先后缀数组SA是后缀数组是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现,能够实现后缀树的很多功能而时间复杂度也不太逊色,并且,它比后缀树所占用的空间小很多。可以说,在信息学竞赛中后缀数组比后缀树要更为实用。 在这之上主要学习了倍增算法来求后缀数组, 下面列举几个在学习中发现的困惑点。 tmp数组储存的是第二关键字从小到大排序...

weixin_30851409的博客 264

在pycharm2021.2中学习opencv图像处理,基于python3.9.7、pycharm完成配置

在pycharm中学习opencv图像处理安装python下载python安装包开始安装安装pycharm社区版下载pycharm开始安装如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 安装python 使用pycharm学习opencv应该是最简单的了,对新手比较友好,

steveqobs 7707

后缀数组入门学习(1):倍增算法基础

满心欢喜来了后缀数组,但是发现自己很懵…… 后缀数组倍增算法的板子并不长,但理解起来相对很困难。 后缀的含义自然不用说了……为了简洁,我们设后缀i为从第i位开始的后缀。 需要这样几个数组: char s[],存字符串(废话),int sa[](本体),xx[](中转数组,存rank),yy[](中转数组,存编号),c[](基排用) 然后我们需要预备知识:基数排序 具体理论就不说了,可以...

weixin_30514745的博客 143

ML307A模组通过MQTT协议接入OneNET平台的AT指令全解析

本文详细解析了ML307A模组通过MQTT协议接入OneNET平台的完整AT指令流程。从平台侧的产品创建、设备添加,到核心难点连接密钥的计算方法,再到模组侧的基础网络附着、MQTT连接配置、数据收发及调试排错,提供了手把手的实战指南,帮助开发者快速实现物联网设备上云。

weixin_29240711的博客 491

YOLOv8-Pose NCNN Android部署优化实践

本文探讨了在Android设备上高效部署YOLOv8-Pose姿态检测模型的优化实践。通过修改Pose头部导出逻辑,分离后处理到C++端实现,并替换SiLU激活函数为ReLU,显著提升了计算效率。具体步骤包括模型结构优化、ONNX导出、NCNN转换与算子融合,最终在Android端实现了30FPS的稳定推理性能。项目提供了完整的优化思路和实现方案,对移动端AI应用开发具有参考价值。

FJN110的博客 323

后缀数组入门

整理自《后缀数组——处理字符串的有力工具》

Confidence的专栏 1941

Agentic AI应用架构师如何提升AI应用的灵活性

可扩展性(Scalability):快速添加新功能或扩展任务范围(如Agent从“客服”扩展到“供应链管理”);可修改性(Modifiability):调整Agent的决策逻辑或动作策略,无需重构整个系统;鲁棒性(Robustness):在环境异常或数据噪声下保持性能稳定;自适应(Self-Adaptation):自主学习新场景,无需人工干预。状态空间(S):Agent能感知的所有内部/外部状态(如用户需求、环境数据);动作空间(A):Agent能执行的所有动作(如调用工具、发送消息);

项目管理的博客 581

算法学习:后缀自动机转后缀树转后缀数组

算法学习:后缀自动机转后缀树转后缀数组 引入 其实这是一篇水文 想要学后缀自动机的话去查2012年noi冬令营陈立杰讲稿 顺便说一句,讲稿上有一些错误,多翻几篇博客加深理解。 今天这里主要要讲的是后缀自动机如何转后缀树和后缀数组 后缀树 这里首先需要提一下后缀树的概念 后缀树其实相当于把所有的后缀插入一颗Trie树 然而时空复杂度都是O(N^2)的 所以我们可以把这可T

maxtir的博客 3205

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

后缀树&后缀数组&LCP

后缀树: 字符串匹配算法一般都分为两个步骤,一预处理,二匹配。 KMP和AC自动机都是对模式串进行预处理,后缀树和后缀数组则是对文本串进行预处理。 后缀树的性质: 存储所有 n(n-1)/2 个后缀需要 O(n) 的空间,n 为的文本(Text)的长度; 构建后缀树需要 O(dn) 的时间,d 为字符集的长度(alphabet); 对模式(Pattern)的查询需要 O(dm) 时间,...

CSer 2299

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

后缀数组

题目很简单,就是给出一个字符串,把这个字符串的所有非空后缀从小到大排序后,按顺序输出后缀的第一个字符在原串中的位置。 样例 输入样例: ababa 输出样例: 5 3 1 4 2 解释: 排好序后为: a aba ababa ba baba 暴力肯定不行啦! 这里我们使用一个叫后缀数组的东西 PS:搞懂模版还要感谢大佬zhangjianweivv的博客! 什么是后缀数组? ...

殇 1888

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

后缀树及后缀数组

后缀树: 后缀树是一种数据结构,它支持有效的字符串匹配和查询。 一个具有m个词的字符串S的后缀树T,就是一个包含一个根节点的有向树,该树恰好带有m个叶子,这些叶子被赋予从1到m的标号。 每一个内部节点,除了根节点以外,都至少有两个子节点,而且每条边都用S的一个非空子串来标识。出自同一节点的任意两条边的标识不会以相同的词开始。后缀

E.G的专栏 2471

后缀数组学习笔记

后缀数组总结

Speknighter的专栏 1050

后缀数组 学习笔记

后缀数组定义搞懂定义是学习后缀数组的关键。 子串:字符串 S 的子串 r[i..j] ,i ≤ j ,表示 r 串中从 i 到 j 这一段,就是顺次排列r[i],r[i+1],…,r[j]形成的字符串。 后缀:后缀是指从某个位置 i 开始到整个串末尾结束的一个特殊子串。字符串 r 的从 第 i 个字 符 开 始 的 后 缀 表 示 为 Suffix(i) ,也就是Suffix(i)=r[i..l

zyf2000 1424

后缀排序【后缀数组入门题】

后缀数组真的是好难理解阿,我觉得我一辈子都看不懂了。只能靠模板过日子。 这是一篇我觉得很好的博客:https://www.cnblogs.com/zwfymqz/p/8413523.html#_labelTop 题目链接:https://www.luogu.org/problemnew/show/P3809 题目大意:读入一个长度为n的由大小写英文字母或数字组成的字符串,请把这...

a6334167的博客 239

后缀数组学习

学习后缀数组的两份必备资料:

u011276914的专栏 961

后缀数组 从零基础到入门

给定一个长度为nnn的字符串sss,将其nnnsa[i]sa[i]sa[i]表示排名为iii的后缀的起始位置rk[i]rk[i]rk[i]表示起始位置为iii的后缀的排名这就是后缀数组的组成部分,一定要熟记这两个定义qwq。sa[rk[i]]=isa[rk[i]]=i,即排名为(起始位置为iii的后缀的排名)的后缀的起始位置是iii(不打括号就太拗口了rk[sa[i]]=irk。

zcxxn的博客 563
上一篇: Count primes
下一篇: 有多少个不同的子串?-- 后缀数组
Code--Dream
博客等级 码龄11年 53粉丝 100原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值