后缀数组基础题套路赏析

好久没写博客了,最近学了一下后缀数组,感觉收获颇丰,于是想写一篇博客纪念一下。特此申明一下,这里用的板子是YZH大佬的SAIS模板,然后小标题和题目用的是罗穗骞大佬2009年国集论文中的标题和例题,%%%。

单个字符串的相关问题

不可重叠最长重复子串

首先当然是对所有后缀进行排序,然后我们考虑二分答案,假设当前的长度是 l,那么我们可以把排好序的后缀分成几段,其中每一段的lcp(height)都是大于等于l的,于是我们记录一下每一段后缀中rl(sa)的最大值和最小值,如果最大值和最小值的差大于l,那么就说明有不重叠的重复子串,反之则不然,这样的做法是O(nlogn)的。当然,我们还可以有O(n)的做法,在尺取的同时,用单调队列维护一下rl(sa)的最大值和最小值,并且答案就是所有符合条件的lcp(height)的最大值。

Musical Theme

code

可重叠的k次最长重复子串

首先可以用同上题的做法,二分答案l,对于lcp(height)大于等于l的每一段,看看是否长度超过k,同样,这个方法的复杂度是O(nlogn)的。但是我们可以发现,用尺取,每次取长度为k的一段,同样可以把复杂度优化到O(n)

Milk Patterns

code

子串的个数

我们可以发现,对于后缀排序是i的后缀,以rl[i](sa[i])作为开头,并且以lcp[i](height[i])及其之前最为结尾的所有子串都会被重复计算,于是我们就不去记这一段对答案的贡献,于是我们所要求的答案就是i=1nnrl[i]+1lcp[i],显然这样的做法的复杂度是O(n)的。

DISUBSTR - Distinct Substrings

code

最长回文子串

我们考虑把一整个字符串复制一段并且翻转,接在原字符串的后面,中间用一个没出现过的字符连接,然后我们对这个新的字符串进行后缀排序,于是我们可以通过枚举中心节点来更新答案,其中中心节点需要根据长度的奇偶性来分类枚举,由于ST表预处理的复杂度是O(nlogn)的,所以这个做法的整体复杂度也是O(nlogn)的。当然,如果能够把RMQ的复杂度降为O(1),那么就可以把整体复杂度降到O(n),具体的话就是笛卡尔树+Tarjan

Palindrome

code

连续重复子串

通过观察可以发现,如果一个串的连续重复子串的长度为l,那么有串s[1]s[l+1]lcp等于nl,所以就只需要枚举一下总长度的因子就行,然后lcp可以用ST表求得,这样做的复杂度是O(nlogn)的。当然还能进行优化,由于RMQ的一端是固定的,于是可以用一个数组O(n)处理,这样就可以把复杂度降到O(n)

Power Strings

code

重复次数最多的连续重复子串

我们考虑枚举长度l为重复周期,那么就可以发现s[1],s[1+l],,s[1+x×l]一定会在一个连续重复子串中,于是对于s[1+a×l]s[1+a×l+l],他们的lcp就是最长能往后延伸的长度,如果lcp不能被l整除,就看看能否往前再延伸一小段距离使得当前的答案增加一,然后算一下复杂度是O(i=1nni)O(nlogn)的。

Maximum repetition substring

code

REPEATS - Repeats

code

两个字符串的相关问题

最长公共子串

我们考虑把两段用一个没出想过的字符连起来,把这个新的字符串进行后缀排序。可以发现,最长公共子串一定出现在相邻两串的lcp中,这样的复杂度是O(n)的。

Long Long Message

code

Freedom of Choice

code

长度不小于k的公共子串的个数

我们先按之前的方法连接字符串并且进行后缀排序,然后对于两个位于不同串的后缀,他们对答案的贡献很好处理,但是有这么多后缀,于是考虑怎么优化。我们首先对于每一个串B的后缀,计算它与它之前出现过的串A的后缀对答案的贡献,然后对串A也是同样,同时我们可以用一个单调栈进行优化,这样的复杂度是O(n)的。

Common Substrings

code

多个字符串的相关问题

出现在不小于k个字符串中的最长子串

我们先把所有串都连在一起,并且中间用没出现过的并且互不相同的字符相连,然后对新串进行后缀排序,然后同样我们可以二分长度l,对于lcp大于等于l的每一段,看是否出现在不少于k个串中,这样的复杂度是O(nlogn)的,当然可以参照之前的方法,用尺取+单调队列把复杂度优化到O(n)

Life Forms

code

在每个串中都至少出现两次且不重叠的最长子串

先像之前那样构造新串并进行后缀排序,然后二分答案l,对于lcp大于等于l的每一段,记录在每个串中rl的最大值和最小值,并进行判断即可,这样的复杂度是O(nlogn)的。

PHRASES - Relevant Phrases of Annihilation

code

出现或反转后出现在每个字符串中的最长子串

把每个串都复制一遍并翻转然后用2n个没出现过的且互不相同的字符连接这些字符串,再把新串进行后缀排序,二分长度l,对于lcp大于等于l的每一段,看是否在每个串中都出现过,这样的复杂度同样也是O(nlogn)的。

Substrings

code


__EOF__

本文作者Jerry-Black
本文链接https://www.cnblogs.com/Jerry-Black/p/16617741.html
关于博主:小蒟蒻一只( ̄^ ̄)ゞ
版权声明:转载请注明来源哟~ QAQ
声援博主:UP UP UP !!!
posted @   Jerry_Black  阅读(67)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示