算法笔记——后缀数组

本文详细介绍了后缀数组的构建原理,包括倍增算法的实现,以及最长公共前缀(LCP)的计算。通过算法思路和实现,展示了如何利用后缀数组解决最长重复子串、不同子串个数、最长回文子串等问题。文章还探讨了LCP的性质,如性质1和2,提供了线性时间复杂度的解决方案。
摘要由CSDN通过智能技术生成

后缀指从某个位置开始到字符串末尾的一个子串,用suffix(i)来表示。

后缀数组(suffix array)指将s的所有后缀从小到大排序后,取其下标i放入数组中,该数组就叫做后缀数组。

sa[i]表示排名为i的后缀为suffix(sa[i])

排名数组指suffix(i)在后缀数组中的排名(下标)

rank[i]表示suffix(i)的排名为rank[i]

后缀数组和排名数组是互逆的,可以来回转换。

sa[rank[i]]=i;

suffix(i)排在第t=rank[i]位,排在第t位的后缀来自sa[t]=i;

rank[sa[i]]=i;

排在第i位的后缀来自t=sa[i],suffix(t)排在第rank[t]=i位。

构建后缀数组有两种算法,DC3算法和倍增算法。一般n<=1e6时采用码量较小的倍增算法。此处采用倍增算法。

算法思路

对字符串从每个下标开始的长度为2^{k}的子串进行排序,得到排名。k从0开始每次增加1,当2^{k}\geqslant n时,从每个下标开始的长度为2^{k}的子串都相当于其后缀suffix(i)。每次子串排序利用上一次子串的排名得到。

求解长度为2^{i}的子串排名,将上一次rank值的第i个和第i+1个结合,再进行排序,得到新的rank值

当rank值没有相同值时已经得到了后缀排名,因为通过结合的方法前面的字符串已经确定了大小,无需再排序。

最后将rank数组转化为后缀数组,即suffix[rank[i]]=i;

算法实现

后缀数组的构建中涉及到排序,因为采用倍增算法,因此长度为n的字符串最多需要O(logn)次排序,排序若采用快速排序,则总复杂度为O(nlog^{2}n),而采用基数排序复杂度为O(nlogn),因此此处采用基数排序

1、将每个字符都转换为数字存入ss[],并通过参数传递赋值给x[]数组(相当于排名数组),进行基数排序。为了防止比较时越界,在末尾用0封装。同时将字符串长度n+1

执行基数排序,的到后缀数组sa[]。

注意:大于等于n的部分的排名应与存在的所有排名不同,因为默认的0是有效的排名(排名从0开始),所以将越界的排名赋为-1

//...该步将s[i]转化为初始排名ss[i]
for(int i=0;i<m;i++)    c[i]=0;
for(int i=0;i<n;i++)    c[x[i]=ss[i]]++;//因为初始长度只有1,因此排名直接等于对应的数字
for(int i=1;i<m;i++)    c[i]+=c[i-1];
for(int i=n-1;i>=0;i--)    sa[--c[x[i]]]=i;//记得倒序放入
for(int i=
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值