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

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

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

  

  容易看出,有但愿成为最长公共前缀不小于k的两个后缀必定在同一组。而后对于每组后缀,只须判断每一个后缀的sa值的最大值和最小值之差是否不小于k。若是有一组知足,则说明存在,不然不存在。整个作法的时间复杂度为O(nlogn)。3d

代码:code

 

 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 }

   在此基础上稍加改动能够完成至少出现K次的最长重复子串(可重叠)的题目blog

相关文章
相关标签/搜索