后缀数组应用小结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Akak__ii/article/details/51278533

前言

之前学了后缀数组,这真是一个神奇的东西。早就想总结一些SA的应用,但一直没时间,现在终于抽出空来写一下自己的心得。
本文只讨论后缀数组的一些应用,不一定全面,仅供参考
还不会后缀数组的同学请自学后再看本文,这里不再赘述后缀数组的基础实现
推荐一篇博客,里面对于基础的后缀数组总结的比较到位,YxuanwKeith大神的五分钟搞懂后缀数组!后缀数组解析以及应用
请不要吐槽标题,不知道你五分钟搞不搞得懂,反正我搞不懂 = = 。
下面进入正题。


后缀数组相关应用

单个字符串相关问题

比较常见的思路是先构造后缀数组,然后求Height数组,用这两个来求解。

重复子串问题

可重叠的最长重复子串问题

因为可重复,所以这类问题比较简单。只需要求Height数组的最大值。因为Height[i]表示排名为ii1的后缀的LCP,所以这个LCP一定是重复的,只需要求个最大值就是最长的。时间复杂度是线性的。

不可重叠的最长重复子串问题

有了不可重叠的限制稍微复杂一点,要用到Height数组的性质。先二分答案,将问题转化为判定性问题。假设我们二分的长度为k,那么答案的两个串它们在SA中的之间的Height值都会k(想一想为什么?),所以我们把连续一段Heightk的后缀划分成一段,如果有某一段满足段中最大的SA值与最小值之差大于等于k,那么当前解就是可行的,因为满足这一条件的串一定不重叠。
注意:这种分段的思想在后缀数组相关问题中很常用

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

例:(JZOJ2265. 【Usaco DEC06 Gold】Milk Patterns)给定一个字符串,求至少出现 k 次的最长重复子串。
做法和上面的差不多,还是先二分,但是条件改变了,不是不重叠,而是出现至少k次。只需判断当前段内是否出现k个后缀即可。

子串计数问题

重复出现子串计数问题

例:(JZOJ1598. 文件修复)求一个字符串中有多少个至少出现两次的子串
这是比较简单的SA题,设每个后缀Ranki,其最多能贡献Height[i]Height[i1]个不同重复子串。
Ans=max(Height[i]Height[i1],0)

不相同子串计数问题

例:(spoj694,spoj705)给定一个字符串,求不相同的子串的个数。
和上面思路大相径庭。每个后缀k会产生nSA[k]+1个前缀,但是会重复计数,所以要减去前面相同的前缀,最后就是nsa[k]+1height[k]个子串。

字典序第K子串问题

例:(JZOJ2824. 【GDOI2012】字符串)给出一个字符串S,问该字符串的所有不同的子串中,按字典序排第K的字串。
应该勉强算计数问题吧。。。其实就是不相同子串个数的扩展,算出每个后缀贡献的不同子串个数,在二分找出最终子串位置(必然是某个后缀的前缀)。

连续重复子串问题

连续重复子串问题

例:给定一个字符串 L,已知这个字符串是由某个字符串 S 重复 R 次而得到的,
求 R 的最大值。
比较简单的重复子串问题。枚举串S长度k,如果Rank[1]Rank[k+1]Height=|L|k那么当前答案合法。

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

例:给定一个字符串L,求重复次数最多的连续重复子串。
还是枚举子串长度k,看这个长度对应每个位置(即L[0],L[k],L[k2]...)之间的LCP是否等于k最长能扩到哪里,就是重复出现次数。

多个字符串相关问题

常用做法是将多个串连在一起,并且中间插入不同且没出现过的字符隔开(想一想为什么?)。但是这种题比较多变,不太好总结,只能简述一些例子。

一个字符串在所有字符串中出现次数问题

例:(JZOJ3258. 【TJOI2013】单词)给定N个字符串,求每个字符串在所有字符串中出现的次数。
对于当前字符串S,设其在总串中起始位置为ST[i],那么我们在Height上二分区间[ 1 , Rank[ST[i]] ] , [ Rank[ST[i]]+1 , n ]内满足Height|S|,这之间的后缀数量就是答案。

字符串子串重复出现k次问题

例:(JZOJ3975. 串)给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身)
SA+线段树维护,详见题解。

其他相关问题

字符串不同种连续子串问题

例:(JZOJ4473. 生成魔咒)给定n个操作,每个操作在字符串S尾插入一个字符,求当前操作后共有多少不同种连续子串。
仔细分析,这题要减去前面的操作对当前影响(即重复的连续子串)。这个应该算是“前缀数组”吧。具体来说就是将字符串翻转后求一边SA,此时所得就是原串的前缀数组。然后在线段树维护一下。


后记

这篇博客是在复习之余码的,由于水平有限,难免有疏漏之处,欢迎批评和补充。后续(或许)会有例题及应用的补充。
参考资料:罗穗骞《后缀数组——处理字符串的有力工具》

以上.

展开阅读全文

没有更多推荐了,返回首页