概念
后缀数组,即对于一个串,它的每个后缀按字典序排序后得到的数组。
有两个数组要求:
:排名为 的后缀的开头位置 :以 为开头的后缀的排名
朴素
sort排序一下
优化
倍增优化:我们进行
#include<iostream>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
string a;
int sa[1000005],rk[1000005],tmp[1000005];
int k;
inline bool cmp(int x,int y)
{
if(rk[x]==rk[y]) //前2^(k-1)相等,比较后k个
{
int i=(x+k<=a.size()?rk[x+k]:-1); //防止越界
int j=(y+k<=a.size()?rk[y+k]:-1);
return i<j;
}
return rk[x]<rk[y];
}
void GetSark()
{
for(int i=0;i<=a.size();i++) //初始化
{
sa[i]=i;
rk[i]=(i<a.size()?a[i]+1:0);
}
for(int i=1;i<=a.size();i=i*2)
{
k=i;
sort(sa,sa+a.size()+1,cmp); //基排懒了
tmp[sa[0]]=0; //暂存rk
for(int z=1;z<=a.size();z++)
{
tmp[sa[z]]=tmp[sa[z-1]]+(cmp(sa[z-1],sa[z])?1:0); //如果比上一个大,排名就增加
}
for(int z=0;z<=a.size();z++)
{
rk[z]=tmp[z]; //复制
}
}
}
signed main()
{
cin>>a;
GetSark();
for(int i=a.size();i>=1;i--) //注意,最后有空串
{
sa[i]++;
rk[i]=rk[i-1];
}
for(int i=1;i<=a.size();i++)
{
cout<<sa[i]<<' '<<rk[i]<<endl;
}
}
应用
在字符串
二分排名即可
bool find(string S,string T)
{
int l=0,r=S.size(),ans;
while(l<=r)
{
int mid=r+l>>1;
if(S.compare(sa[mid],T.size(),T)==-1)
{
l=mid+1;
}
else
{
ans=mid;
r=mid-1;
}
}
return S.compare(sa[ans],T.size(),T)==0;
}
LCP
LCP即最长公共前缀
SA排完序后,有:
height
后缀数组的另一应用
对于
则
void get_height()
{
int k=0;
for(int i=1;i<=a.size();i++)
{
if(k)
{
k--;
}
int j=sa[rk[i]-1];
while(a[i+k]==a[j+k]) k++;
height[rk[i]]=k;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通