字符串----不可重叠的最长重复子串

题目:给定一个字符串,求最长重复子串,这两个子串不能重叠。例如,str = "acdcdcdcd",则不可重叠的最长子串为"cdcd"。

思路:二分枚举+height数组分组。这道题的思想很巧妙,后面要仔细推敲。先二分答案,把题目变成判定性问题:判断是否存在两个长度为k的子串是相同的,且不重叠。解决这个问题的关键还是利用height数组。把排序后的后缀分成若干组,其中每组的后缀之间的height值都不小于k。例如,字符串为“aabaaaab”,当k=2时,后缀分成了4组,如图所示。

  

  容易看出,有希望成为最长公共前缀不小于k的两个后缀一定在同一组。然后对于每组后缀,只须判断每个后缀的sa值的最大值和最小值之差是否不小于k。如果有一组满足,则说明存在,否则不存在。整个做法的时间复杂度为O(nlogn)。

代码:

 1 public class MaxRepeatSubString2 {
 2
 3     public static void main(String[] args) {
 4         int res = maxRepeatSubString2("1x23231923263");
 5         System.out.println(res);  // 输出 3
 6     }
 7
 8     /**
 9      * 不允许交叉
10      *
11      * @param src
12      * @return
13      */
14     public static int maxRepeatSubString2(String src) {
15         SuffixArray.Suff[] sa = SuffixArray.getSa2(src);
16         int[] height = SuffixArray.getHeight(src, sa);
17         int l = 0;
18         int r = height.length;
19         int ans = 0;
20         while (l <= r) {
21             int mid = l + ((r - l) >> 1);// check的重叠长度
22             if (check(height, sa, mid)) {
23                 if (mid == height.length / 2) {
24                     return mid;
25                 }
26                 l = mid + 1;
27                 ans = mid;
28                 // return mid;
29             } else {
30                 r = mid - 1;
31             }
32         }
33         return ans;
34     }
35
36     /**
37      * 用len将height分组,小于组和大于等于组交替
38      * 在大于组中更新最大最小原始小标,大转小的时候检查上一个大于组是否满足不重叠
39      * 在小于组中,只需持续地将原始下标付给max和min,这样小转大的时候,可以保留小于组最后一个元素的下标
40      */
41     private static boolean check(int []height,SuffixArray.Suff[]sa,int len){
42         int minIndex = sa[0].index;
43         int maxIndex = sa[0].index;
44         for(int i = 1;i<height.length;i++){
45             int index = sa[i].index;
46             if(height[i]>=len){ // lcp 大于 len
47                 minIndex = Math.min(minIndex,index);
48                 maxIndex = Math.max(maxIndex, index);
49             } else {
50                 if (maxIndex - minIndex >= len) {
51                     return true;
52                 }
53                 maxIndex = index;
54                 minIndex = index;
55             }
56         }
57         return (maxIndex - minIndex) >= len;
58     }
59
60 }

原文地址:https://www.cnblogs.com/xiaoyh/p/10328219.html

时间: 2024-08-03 22:03:53

字符串----不可重叠的最长重复子串的相关文章

后缀数组(至少重复k次的可重叠的最长重复子串)—— POJ 3882

对应POJ 题目:点击打开链接 Stammering Aliens Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Description Dr. Ellie Arroway has established contact with an extraterrestrial civilization. However, all efforts to decode their m

poj 1743 二分答案+后缀数组 求不重叠的最长重复子串

题意:给出一串序列,求最长的theme长度 (theme:完全重叠的子序列,如1 2 3和1 2 3  or  子序列中每个元素对应的差相等,如1 2 3和7 8 9) 要是没有差相等这个条件那就好办多了,直接裸题. 一开始想了个2B方法,后来发现真心2B啊蛤蛤蛤 1 for i=1 to 88 do 2 { 3 for j=1 to length 4 { 5 r2[j]=r[j]+i; 6 if (r2[j]>88) r2[i]-=88; 7 } 8 把新序列r2连接到原序列r的后面 9 pr

POJ 1743 不可重叠的最长重复子串

原问题,其实是找最长的相似子串,所谓相似就是一个子串每个值加上一个偏移值可以得到另一个子串. 我们先求原数组的差值数组,对新数组求后缀数组,二分答案,判定是否有某个Height数组中的sa最小值与最大值之差大于当前枚举的子串长度. #include <iostream> #include <vector> #include <algorithm> #include <string> #include <string.h> #include <

【POJ1743】不可重叠最长重复子串

题意:求一个字符串里两个不重叠的最长重复子串 代码如下: 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 7 int sa[20010],rank[20010],y[20010],Rsort[20010]; 8 int wr[20010],a[20010],height[20010],n; 9 10

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

题目链接:https://cn.vjudge.net/contest/318888#problem/B 题意: 约翰注意到奶牛产奶的之类是不断变化的,虽然他不能预测从当天到下一天的变化情况但是他知道变化是有规律的,牛奶的质量由一个整数表示,范围从0到1000000,现在给定一个长度为n的序列,要求找到一个最大子序列,该子序列重复出现至少k次,各个出现部分可有重叠,求最长的长度.简单来说就是可重叠的k 次最长重复子串. 简单来说就是求可重叠的k次最长重复子串 思路: 这题首先先看数据的范围,发现相

面试题[后缀数组]: 最长重复子串

题目:给定一个字符串,求出最长重复子串. 这个题目可以用后缀数组来解:对后缀数组排好序,这样重复的子串就在相邻的后缀中找就可以了.我的C++代码实现如下: class Solution { public: string LongestRepeatingSubstring(string str) { size_t len = str.size(); vector<string> SuffixArray(len); for (size_t i = 0; i < len; ++i) Suffi

POJ 3261 可重叠的 k 次最长重复子串【后缀数组】

这也是一道例题 给定一个字符串,求至少出现 k 次的最长重复子串,这 k 个子串可以重叠.算法分析:这题的做法和上一题差不多,也是先二分答案,然后将后缀分成若干组.不同的是,这里要判断的是有没有一个组的后缀个数不小于 k.如果有,那么存在k 个相同的子串满足条件,否则不存在.这个做法的时间复杂度为 O(nlogn). Source Code: //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include

POJ - 3261 Milk Patterns (后缀数组求可重叠的 k 次最长重复子串)

Description Farmer John has noticed that the quality of milk given by his cows varies from day to day. On further investigation, he discovered that although he can't predict the quality of milk from one day to the next, there are some regular pattern

poj 3261 求可重叠的k次最长重复子串

题意:求可重叠的k次最长重复子串的长度 链接:点我 和poj1743差不多 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define MOD 1000