这篇博客不打算讲多么详细,网上关于后缀数组的blog比我讲的好多了,这一篇博客我是为自己加深印象写的。

给你们分享了那么多,容我自私一回吧~

参考资料:这位dalao的blog

一、关于求SuffixArray的一些变量定义:

1. sa[i]=j,表示第i名的后缀从j开始

**存的是下标**

2. rnk[i]=j,从i开始的后缀是第j名的

**与sa为互逆运算,存的是值**

3. tp[i]=j, 第二关键字为i的后缀从j开始

**可理解为第二关键字的SA,存的是下标**

插入解释一下第一关键字和第二关键字:

我们要对所有的后缀进行排序,怎么排呢?

开始时,我们每个字符的后缀存的只有它自己,所以它后缀的大小就是它的ASCII码。

我们把每个字符i看成(s[i],i)的二元组,如果我们直接丢pair<int,int>里面然后std::sort,

这样的时间复杂度是O(log^2 n)的,显然不够优秀。

所以就需要用到基数排序RadixSort,不了解的自行百度。

再使用倍增法,就可以使我们排序的时间复杂度降低到O(logn)。

所以我们要对每个后缀的前两个字母进行排序,第一个字母的相对关系已经得到了。

第i个后缀的第二个字母,就是第i+1个后缀的第一个字母,利用这个关系我们第二个字母的相对关系也就知道了。

我们的tp数组就是用来记录它的,rnk[i]表示上一轮中第i个后缀的排名。

这里引用神仙attack的一句话,我觉得讲的非常到位:

对于一个长度为w的后缀,你可以形象的理解为:

第一关键字针对前w2个字符形成的字符串,第二关键字针对后w2个字符形成的字符串

然后对每个后缀的前4个字母组成的字符串排序,前8个,前16个...这就是倍增法求SA的流程了。

给出RadixSort的代码:

void RadixSort(int a[],int b[]){//基数排序
for(int i=;i<=m;i++)tax[i]=;
for(int i=;i<=n;i++)tax[a[i]]++;
for(int i=;i<=m;i++)tax[i]+=tax[i-];
for(int i=n;i>=;i--)sa[tax[a[b[i]]]--]=b[i];
}

实在不能理解RadixSort也没有关系,代码很短

再给出求SA的代码:

bool cmp(int *r,int a,int b,int k){
return r[a]==r[b]&&r[a+k]==r[b+k];
}
void getSA(int a[],int b[]){
for(int i=;i<=n;i++)
m=max(m,a[i]=s[i]-''),b[i]=i;
RadixSort(a,b);
for(int p=,j=;p<n;j<<=,m=p){
p=;
for(int i=;i<=j;i++)b[++p]=n-j+i;
for(int i=;i<=n;i++)if(sa[i]>j)b[++p]=sa[i]-j;
RadixSort(a,b);
int *t=a;a=b;b=t;
a[sa[]]=p=;
for(int i=;i<=n;i++)
a[sa[i]]=cmp(b,sa[i],sa[i-],j)?p:++p;
}
}

关于代码的解释,有时间再填坑。本蒟蒻要学的算法还很多...SA就粗略地理解一下好了

开始填坑,先补充一个东西叫height数组。

height[i]表示排名为i的后缀和排名为i-1的后缀的最长公共前缀LCP。

暴力求解时间复杂度是O(n^2),根据一个性质height[i+1]>=height[i]-1

可以O(n)时间内求出height数组,具体代码:

void getHeight(){
for(int i=,j=;i<=n;i++){
if(j)j--;
while(s[i+j]==s[sa[rnk[i]-]+j])j++;
height[rnk[i]]=j;
}
}

关于这个height数组,它可以干什么,给出一张列表:

两个后缀的最大公共前缀

lcp(x,y)=min(heigh[x−y])lcp(x,y)=min(heigh[x−y]), 用rmq维护,O(1)查询

可重叠最长重复子串

height数组里的最大值

不可重叠最长重复子串

首先二分答案x,对height数组进行分组,保证每一组的最小height都>=x

依次枚举每一组,记录下最大和最小长度,若sa[max]−sa[min]>=x那么可以更新答案

本质不同的子串的数量

枚举每一个后缀,第i个后缀对答案的贡献为len−sa[i]+1−height[i]

浅谈后缀数组SA的更多相关文章

  1. 后缀数组(SA)总结

    后缀数组(SA)总结 这个东西鸽了好久了,今天补一下 概念 后缀数组\(SA\)是什么东西? 它是记录一个字符串每个后缀的字典序的数组 \(sa[i]\):表示排名为\(i\)的后缀是哪一个. \(r ...

  2. 后缀数组SA学习笔记

    什么是后缀数组 后缀数组\(sa[i]\)表示字符串中字典序排名为\(i\)的后缀位置 \(rk[i]\)表示字符串中第\(i\)个后缀的字典序排名 举个例子: ababa a b a b a rk: ...

  3. 后缀数组SA入门(史上最晦涩难懂的讲解)

    参考资料:victorique的博客(有一点锅无伤大雅,记得看评论区),$wzz$ 课件(快去$ftp$%%%),$oi-wiki$以及某个人的帮助(万分感谢!) 首先还是要说一句:我不知道为什么我这 ...

  4. bzoj3796(后缀数组)(SA四连)

    bzoj3796Mushroom追妹纸 题目描述 Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意——写情书.考虑到自己的表达能力,Mushroom决定不手写情书.他从 ...

  5. [笔记]后缀数组SA

    参考资料这次是真抄的: 1.后缀数组详解 2.后缀数组-学习笔记 3.后缀数组--处理字符串的有力工具 定义 \(SA\)排名为\(i\)的后缀的位置 \(rk\)位置为\(i\)的后缀的排名 \(t ...

  6. 【字符串】后缀数组SA

    后缀数组 概念 实际上就是将一个字符串的所有后缀按照字典序排序 得到了两个数组 \(sa[i]\) 和 \(rk[i]\),其中 \(sa[i]\) 表示排名为 i 的后缀,\(rk[i]\) 表示后 ...

  7. 后缀数组SA

    复杂度:O(nlogn) 注:从0到n-1 const int maxn=1e5; char s[maxn]; int sa[maxn],Rank[maxn],height[maxn],rmq[max ...

  8. 洛谷2408不同字串个数/SPOJ 694/705 (后缀数组SA)

    真是一个三倍经验好题啊. 我们来观察这个题目,首先如果直接整体计算,怕是不太好计算. 首先,我们可以将每个子串都看成一个后缀的的前缀.那我们就可以考虑一个一个后缀来计算了. 为了方便起见,我们选择按照 ...

  9. 洛谷4248 AHOI2013差异 (后缀数组SA+单调栈)

    补博客! 首先我们观察题目中给的那个求\(ans\)的方法,其实前两项没什么用处,直接\(for\)一遍就求得了 for (int i=1;i<=n;i++) ans=ans+i*(n-1); ...

随机推荐

  1. Protocol Buffers学习笔记

    Protocol Buffers学习笔记 1. 简介 Protocol Buffers是google发明的一种数据交换格式,独立于语言,独立于平台.与其他的数据交换格式有所不同,Protocol Bu ...

  2. 设顺序表中的数据元素递增有序,试着写一算法,将x插入到顺序表上的适当位置上,以保持该表的有序性。

    原创,转载请注明出处.https://www.cnblogs.com/yangf428/p/11254370.html 天勤例题[2-1]: 设顺序表va中的数据元素递增有序.试写一算法,将x插入到顺 ...

  3. @Transactional注解不生效的原因总结(整理网上和自己遇到的解决方案)

    1.问题背景 今天做项目,发现配置好@Transactional后,没有生效,事务没有回滚,即便在网上查资料,也没有解决,好像网上没有人发过我遇见的这种情况的帖子. 2.自己遇到的情况分析 代码结构图 ...

  4. UML期末复习题——2.1:Use Case Diagram

    第一题:用例图 重要概念: 1.采用参与者和参与者目标的观点: 一组用例实例,每个实例是系统所执行的一系列活动,以此产生对特定参与者具有价值的客观结果. 短语“对特定参与者具有价值的客观结果”是细微而 ...

  5. CentOS7下安装php-redis扩展

    yum -y install php70w-pecl-redis

  6. v-if与v-show的区别?

    v-if的显示和隐藏实在dom里创建和消除dom节点 v-show是用css样式的display来控制dom节点的显示和隐藏 相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染 ...

  7. create-react-app 工程,如何修改react端口号?

    概要: 3000端口是webpack配置里面写的,可以通过传递一个PORT全局变量,来修改这个端口.当然,您还可以在node_modules/react-scripts/目录下面,批量搜索替换3000 ...

  8. 004-log-common-logging,Apache整合日志框架JCL门面框架、JCL+log4j

    一.概述 Jakarta Commons Logging (JCL)提供的是一个日志(Log)接口(interface),同时兼顾轻量级和不依赖于具体的日志实现工具.它提供给中间件/日志工具开发者一个 ...

  9. Java8 根据对象某个属性值去重

    list中的对象某个属性存在重复时将重复的对象去重 //根据skuAttrValueName值去重 List<SkuValue> uniqueSkuValues = skuValues.s ...

  10. (IStool)软件打包时当文件存在时不覆盖文件(配置文件)

    需求:程序实际使用过程中有些配置信息是需要用户手动配置的,不同客户使用配置信息也不同,所以软件发布前需要考虑这个问题,覆盖安装时需要忽略这些配置文件 实现:当对应的目录下由此文件的时候不覆盖此文件 [ ...