SA后缀数组学习笔记
什么是后缀数组
后缀数组主要是用来处理字符串的,分为两种方法:倍增法以及 DC3,但由于倍增法通俗易懂,码量小,常数小,所以今天这篇文章我就只介绍倍增法(不可能是因为我不会 DC3)
前缀知识
No.1 基数排序
毕竟sort
排序需要
跟桶排序差不了多少,思想就是:将整数按位数切割成不同的数字,然后按每个位数分别比较。按每个位数从低位数到高位数分别比较。
然后在后缀数组中,我们就借用了这个思想来处理一个二元组,这之后我们还会接着讲。
No.2 文章中的数组介绍
,即第二关键字排名为i的后缀的位置
倍增法
我们上面不是提到了倍增吗,那么这个算法肯定需要
如图所示,秉承着基数排序的思想,我们先弄出一个二元组,用两个长度为
然后在增加二元组中的两个子串的长度,但一个一个地增加太慢了,于是就运用倍增。继续进行排序:
为什么倍增是正确的呢?
假如当前排序的长度为
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;
char ch;
ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-f;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
return x*f;
}
const int N=1114514;
char s[N];
int n,m=500,t;
int rak[N],tp[N],tag[N],sa[N];
inline void Radix_sort(){
for(int i=1;i<=m;++i) tag[i]=0;
for(int i=1;i<=n;++i)++tag[rak[i]];
for(int i=1;i<=m;++i) tag[i]+=tag[i-1];
for(int i=n;i>=1;--i) sa[tag[rak[tp[i]]]--]=tp[i],tp[i]=0;
}
inline void SA(){
int p=0;
for(int i=0;i<=m;++i) tag[i]=0;
for(int i=1;i<=n;++i) rak[i]=(int)s[i],tp[i]=i;
Radix_sort();
for(int k=1;k<=n;k<<=1){
p=0;
for(int i=0;i<=m;++i) tag[i]=tp[i]=0;
for(int i=n-k+1;i<=n;++i) tp[++p]=i;
for(int i=1;i<=n;++i)
if(sa[i]>k)
tp[++p]=sa[i]-k;
Radix_sort();
swap(rak,tp);
rak[sa[1]]=1;
p=1;
for(int i=2;i<=n;++i)
rak[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+k]==tp[sa[i]+k])?p:++p;
if(p>=n) break;
m=p;
}
}
signed main(){
scanf("%s",s+1);
n=strlen(s+1);
SA();
for(int i=1;i<=n;++i)
printf("%lld ",sa[i]);
return 0;
}
建议下一篇阅读 LCP与height数组
6666
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具