从SA入门到SAM精通
SA
基本应用
读入一个长度为
解法
1.将每个后缀取出来,直接排序
2.用hash二分LCP比较下一位,
3.倍增求后缀数组,
4.高级方法求后缀数组,
倍增
先比较每个后缀的第一位,再比较前两位,前四位...
问题在于如何快速比较前两位,前四位。
一个有趣的性质是在比较
基数排序
正常基数排序,是按数位从高到低依次比较大小,比如说三位数,就先比较百位的数字,将百位为
SA的基数排序,就是相当于只有两位数来排序。
代码实现
代码比较抽象要多理解,多思考
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m,sa[N],rk[N],x[N],y[N],cnt,num;
char s[N];
void SA()
{
for(int i=1;i<=n;i++)rk[x[i]=s[i]]++;//rk辅助数组,x是上一层的排名
for(int i=1;i<=m;i++)rk[i]+=rk[i-1];
for(int i=n;i>=1;i--)sa[rk[x[i]]--]=i;//正序倒序都可以,sa是排名为i的后缀的起始下标
for(int k=1;k<=n;k<<=1)
{
cnt=0;
for(int i=n-k+1;i<=n;i++)y[++cnt]=i;//没有后一半是最强的,最靠前的
for(int i=1;i<=n;i++)if(sa[i]>k)y[++cnt]=sa[i]-k;//如果可以做后一半,就做
//正序枚举,因为y的顺序是后一半从小到大的顺序
for(int i=1;i<=m;i++)rk[i]=0;//清零
for(int i=1;i<=n;i++)rk[x[i]]++;//根据前一半
for(int i=1;i<=m;i++)rk[i]+=rk[i-1];
for(int i=n;i>=1;i--)sa[rk[x[y[i]]]--]=y[i],y[i]=0;//后一半更大的在前一半相同时排后面
swap(x,y);//y临时存一下上一层x的值。
x[sa[1]]=1,num=1;
for(int i=2;i<=n;i++)
{
x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;//确定这一层的排名
}
if(num==n)break;//分完了
m=num;
}
for(int i=1;i<=n;i++)cout<<sa[i]<<' ';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>s+1;
n=strlen(s+1),m=150;
SA();
return 0;
}
进阶应用
LCP与hieght数组
LCP:最长公共前缀,
思考题:如果一直想不出来是正常的不然还有什么讲的必要)
要先引入一个新数组
那我们先研究它的性质,我们可以发现
我们先将从
我们可以去掉开头字母,则
这样就可以继承前面的信息暴力改。
void geth()
{
int kk=0;
for(int i=1;i<=n;i++)x[sa[i]]=i;
for(int i=1;i<=n;i++)
{
if(x[i]==1)continue;
if(kk)kk--;
int j=sa[x[i]-1];
while(i+kk<=n&&j+kk<=n&&s[i+kk]==s[j+kk])kk++;
hi[x[i]]=kk;
}
}
时间复杂度,
回到最开始的地方,现在一直
可重叠最长重复子串
规定长度就是区间
不可重叠最长重复子串
首先二分答案
依次枚举每一组,记录下最大和最小长度,如果相减大于
本质不同子串
子串是后缀的前缀,后缀拍完序之后,每次新增的只有除LCP以外的子串。
所以总数为
比较子串大小
求出两子串所属的后缀的LCP,如果LCP比长度大则一个是另一个的子串,所以按长度即可比较大小,如果不是,则直接根据
更多
SAM
字符串的 SAM 可以理解为给定字符串的所有子串的压缩形式。值得注意的事实是,SAM 将所有的这些信息以高度压缩的形式储存。对于一个长度为 n$ 它的空间复杂度仅为
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)