zoukankan      html  css  js  c++  java
  • [LeetCode] 1044. Longest Duplicate Substring

    Given a string S, consider all duplicated substrings: (contiguous) substrings of S that occur 2 or more times.  (The occurrences may overlap.)

    Return any duplicated substring that has the longest possible length.  (If S does not have a duplicated substring, the answer is "".)

    Example 1:

    Input: "banana"
    Output: "ana"
    

    Example 2:

    Input: "abcd"
    Output: ""

    Note:

    1. 2 <= S.length <= 10^5
    2. S consists of lowercase English letters.

    最长重复子串。题意是给一个input字符串,请你找出最长的重复子串。比如第一个例子,ana就出现了不止一次,且没有再长的子串出现多次的了。

    思路是二分 + Rabin-Karp/rolling hash(滚动哈希)。二分的目的是在于加快找这个子串的速度。首先需要想通一个定理,如果能找到一个较长的重复子串,那么也就不需要再去找较短的重复子串了,因为较长的重复子串里面一定有较短的重复子串。比如ana里面一定包含一个更短的子串an和na。所以如果能在mid这个长度上找到这个重复子串,你就只需要往右边界靠拢去找是否有更长的重复子串而不需要去找更短的子串了。

    rolling hash的目的是在于记录出现的子串并且节省空间。一般情况下的确可以用hashmap或者hashset存储,key是出现过的unique的子串;但是如果input字符串太长,也就意味着子串会很长,这样内存是会不够用的。rolling hash是将一个字符串转化为一个数字存在哈希表里面。rolling hash的实现方式是这样的,比如单词是banana。给每个字母赋值(0 - 25之间的数字),得到b, a, n, a, n, a -> [1, 0, 13, 0, 13, 0]。而计算rolling hash的方式是

    比如b, a, n -> 1 * 100 + 0 * 10 + 13 * 1 = 100 + 0 + 13 = 113,然后113再 % 某一个数字,得到一个更小的数字(应该在Long型范围内)存在哈希表里面。

    我这里只是给出一个例子,展示出rolling hash的概念,但是实际上如果真的只是按数位乘以10,一定会导致哈希冲突,所以做rolling hash的时候需要选择一个比较大的数字来替换10(代码里给的是Integer.MAX_VALUE,%的是256)。

    时间 - ?

    空间O(n) - hashmap

    Java实现

     1 class Solution {
     2     private static final long q = (1 << 31) - 1;
     3     private static final long R = 256;
     4 
     5     public String longestDupSubstring(String S) {
     6         int left = 2;
     7         int right = S.length() - 1;
     8         int start = 0;
     9         int maxLen = 0;
    10 
    11         while (left <= right) {
    12             int len = left + (right - left) / 2;
    13             boolean found = false;
    14 
    15             Map<Long, List<Integer>> map = new HashMap<>();
    16             long hash = hash(S, len);
    17             map.put(hash, new ArrayList<>());
    18             map.get(hash).add(0);
    19             long RM = 1l;
    20             for (int i = 1; i < len; i++) {
    21                 RM = (R * RM) % q;
    22             }
    23 
    24             loop: for (int i = 1; i + len <= S.length(); i++) {
    25                 hash = (hash + q - RM * S.charAt(i - 1) % q) % q;
    26                 hash = (hash * R + S.charAt(i + len - 1)) % q;
    27                 if (!map.containsKey(hash)) {
    28                     map.put(hash, new ArrayList<>());
    29                 } else {
    30                     for (int j : map.get(hash)) {
    31                         if (compare(S, i, j, len)) {
    32                             found = true;
    33                             start = i;
    34                             maxLen = len;
    35                             break loop;
    36                         }
    37                     }
    38                 }
    39                 map.get(hash).add(i);
    40             }
    41             if (found)
    42                 left = len + 1;
    43             else
    44                 right = len - 1;
    45         }
    46         return S.substring(start, start + maxLen);
    47     }
    48 
    49     private long hash(String S, int len) {
    50         long h = 0;
    51         for (int j = 0; j < len; j++)
    52             h = (R * h + S.charAt(j)) % q;
    53         return h;
    54     }
    55 
    56     private boolean compare(String S, int i, int j, int len) {
    57         for (int count = 0; count < len; count++) {
    58             if (S.charAt(i++) != S.charAt(j++))
    59                 return false;
    60         }
    61         return true;
    62     }
    63 }

    LeetCode 题目总结

  • 相关阅读:
    CSP-S 2020 游记
    USACO Mowing the Lawn
    洛谷 P1725 琪露诺
    浅谈单调队列
    浅谈单调栈
    洛谷 P1440 求m区间内的最小值
    POJ 2823 Sliding Window
    洛谷 P1901 发射站
    POJ 2796 Feel Good
    POJ 2559 Largest Rectangle in a Histogram
  • 原文地址:https://www.cnblogs.com/cnoodle/p/13168269.html
Copyright © 2011-2022 走看看