以下内容引自2009国家集训队论文《后缀数组——处理字符串的有力工具》 罗穗骞
最长公共前缀:
height数组的区间最小值。
单个字符串的相关问题
可重叠最长重复子串:
子串就是后缀的一个前缀,所以重复子串就是两个后缀的公共前缀,只需求两个后缀的最大公共前缀,就是height数组的最大值。
不可重叠最长重复子串:
二分答案 k k k,把问题变成判定性问题:判断是否存在两个长度为 k 的子串是相同的,且不重叠。将height按照大小分组,使得每一组的height值都大于等于k,那么最长公共前缀大于等于k的两个后缀只可能出现在同一组中,只需要是否存在某一组后缀中sa的最大值与最小值之差大于等于k。
可重叠k次最长重复子串:
同样二分答案后分组,检测是否存在某一组的后缀个数大于等于k。
或在height数组中选一段长度为k-1的区间,取区间最小值的最大值。
不相同子串个数:
每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数。按照后缀排序后的顺序依次考虑,对于第k个后缀suffix(sa[k]),它将产生n-sa[k]+1个前缀,但其中有height[k]个是和前面相同的,将n-sa[k]+1-height[k]累加即为答案。
最长回文子串:
穷举每一位,然后计算以这个字符为中心的最长回文子串。注意这里要分两种情况,一是回文子串的长度为奇数,二是长度为偶数。两种情况都可以转化为求一个后缀和一个反过来写的后缀的最长公共前缀。具体的做法是:将整个字符串反过来写在原字符串后面,中间用一个特殊的字符隔开。
连续重复子串:
问题描述:已知字符串S是由子串L重复R次得到的,求R的最大值。
穷举字符串 S 的长度 k,然后判断是否满足。判断的时候,先看字符串 L 的长度能否被 k 整除,再看 suffix(1)和 suffix(k+1)的最长公共前缀是否等于 n-k。在询问最长公共前缀的时候,suffix(1)是固定的,所以 RMQ问题没有必要做所有的预处理,只需求出 height 数组中的每一个数到height[rank[1]]之间的最小值即可。
重复次数最多的连续重复子串:
两个字符串的相关问题
这类问题的一个常用做法是,先连接这两个字符串,然后求后缀数组和height 数组,再利用 height 数组进行求解。
最长公共子串:
将第二个字符串写在第一个字符串后面,中间用一个没有出现过的字符隔开,suffix(sa[i-1])和suffix(sa[i])属于不同的串时的height[i]的最大值就是答案。
长度不小于 k 的公共子串的个数:
多个字符串的相关问题
这类问题的一个常用做法是,先将所有的字符串连接起来,然后求后缀数组和 height 数组,再利用 height 数组进行求解。这中间可能需要二分答案。
不小于 k 个字符串中的最长子串:
将 n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组。然后二分答案,将后缀分成若干组,判断每组的后缀是否出现在不小于 k 个的原串中。
每个字符串至少出现两次且不重叠的最长子串:
做法和上题大同小异,也是先将 n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组。然后二分答案,再将后缀分组。判断的时候,要看是否有一组后缀在每个原来的字符串中至少出现两次,并且在每个原来的字符串中,后缀的起始位置的最大值与最小值之差是否不小于当前答案(判断能否做到不重叠,如果题目中没有不重叠的要求,那么不用做此判断)。