字符串----不可重疊的最長重復子串


題目:給定一個字符串,求最長重復子串,這兩個子串不能重疊。例如,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 }

   在此基礎上稍加改動可以完成至少出現K次的最長重復子串(可重疊)的題目


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM