相信做过几道后缀数组题的人都深有体会,求出来的sa、rank数组用处不大,真正有用的是height数组。下面总结一下目前遇到的height数组的用法。
1. 求字符串两后缀最长公共前缀
求后缀i与后缀j的最长公共前缀长度,也就是min(height[rank[i]+1], height[rank[i]+2, ......, height[rank[j]]),假设rank[i] < rank[j]的情况下。只需要证明出传递性就得证,传递性为:如果有三个字符串, 按字典序排序,lcp(1, 3) 等于 min(lcp(1, 2),lcp(2, 3))。排序后前两个字符串第lcp(1, 2)+1位一定不同且存在小于关系,由于第3个字符串大于第2个字符串,所以第3个字符串和第1个字符串前lcp(1, 2)+1位一定不同(分类讨论),所以lcp(1, 3) <= lcp(1, 2),又因为前两个字符串前lcp(1, 2)位相同,只需要比较后两个字符串前lcp(1, 2)位即可,也就是min(lcp(1, 2), lcp(2, 3))。至此证出传递性,由传递性就可得出结论。
2. 求字符串可重叠的最长重复子串长度
给定一个字符串,求至少出现两次的可重叠的最长子串长度。首先如果要最长的话只要找出现两次的就够了,相同长度下如果出现了三次那一定出现了两次,如果出现了两次不一定出现了三次。而出现两次可重叠的子串长度一定是两任意后缀最长公共前缀的最大值,用反证法很容易证得。由于两后缀的最长公共前缀长度是区间height的最小值,因此答案就是height数组中的最大值。
3. 求字符串不重复的子串个数
显然总共的子串有n*(n+1)/2个,n为字符串长度。只需要剔除重复的子串即可,模拟可得重复子串数为sum(height[i]),证明见:(2条消息) [好题][height][后缀数组]New Distinct Substrings SPOJ SUBST1_Cloth的博客-CSDN博客
因此最终答案为n*(n+1)/2-sum(height[i])。
4. 求两字符串最长公共子串
将两字符串相连,中间加一个不会出现的字符以防越界,之后把height跑出来,答案就是后缀开始位置在两侧的最大height值,同时利用该思想还可以求k个字符串的最长公共子串。证明见:(2条消息) [后缀数组][最长公共子串]Long Long Message POJ2774_Cloth的博客-CSDN博客