This approach leverages binary search in conjunction with the Rabin-Karp (rolling hash) algorithm to find the longest duplicate substring within a given string.
We perform binary search on the length of the possible substring, starting from 1 to length of s
-1. For each mid-length obtained from the binary search, we use a rolling hash function to hash each substring of length mid
. This hash is used to quickly identify duplicates due to its constant time complexity for fixed-length substrings.
Time Complexity: O(n log n), where n is the length of the string. The binary search takes O(log n), and for each midpoint, hashing takes O(n).
Space Complexity: O(n), primarily for storing hash values and powers of base.
1import java.util.HashSet;
2
3public class Solution {
4 private static final int MOD = 10000007;
5 private static final int BASE = 26;
6
7 public String longestDupSubstring(String s) {
8 int n = s.length();
9 int left = 0, right = n - 1;
10 String result = "";
11
12 while (left <= right) {
13 int mid = left + (right - left) / 2;
14 String dup = findDup(s, mid);
15 if (!dup.equals("")) {
16 left = mid + 1;
17 result = dup;
18 } else {
19 right = mid - 1;
20 }
21 }
22 return result;
23 }
24
25 private String findDup(String s, int len) {
26 HashSet<Integer> seen = new HashSet<>();
27 long hash = 0, power = 1;
28 for (int i = 0; i < len; i++) {
29 hash = (hash * BASE + s.charAt(i) - 'a') % MOD;
30 if (i < len - 1) power = (power * BASE) % MOD;
31 }
32
33 seen.add((int) hash);
34 for (int i = len; i < s.length(); i++) {
35 hash = (hash * BASE - power * (s.charAt(i - len) - 'a') % MOD + MOD) % MOD;
36 hash = (hash + s.charAt(i) - 'a') % MOD;
37 if (seen.contains((int) hash)) {
38 return s.substring(i - len + 1, i + 1);
39 }
40 seen.add((int) hash);
41 }
42 return "";
43 }
44
45 public static void main(String[] args) {
46 Solution sol = new Solution();
47 String s = "banana";
48 System.out.println(sol.longestDupSubstring(s));
49 }
50}
51
Utilizing Java's HashSet
, this code performs a binary search to identify the duplicate substring's maximum length. The findDup
method hashes substrings and checks for duplicates to return the longest valid substring.
This method involves constructing a suffix array from the input string and then performing binary search on the suffixes to find the longest duplicate substring.
Using suffix arrays, we can efficiently sort and group starting indices of the given string. Then, by employing binary search, we determine the largest-length substring that repeats. The Longest Common Prefix (LCP) array helps in assessing the similarity of suffixes at each binary search step.
Time Complexity: O(n^2 log n), primarily due to the sorting step where n is the length of the input string.
Space Complexity: O(n^2), largely for storing pointers to suffixes.
1class Solution:
2 def longestDupSubstring(self, s: str) -> str:
3 suffixes = [s[i:] for i in range(len(s))]
4 suffixes.sort()
5
6 def common_prefix_length(s1, s2):
7 min_len = min(len(s1), len(s2))
8 for i in range(min_len):
9 if s1[i] != s2[i]:
10 return i
11 return min_len
12
13 result = ""
14 for i in range(1, len(s)):
15 len_common = common_prefix_length(suffixes[i - 1], suffixes[i])
16 if len_common > len(result):
17 result = suffixes[i][:len_common]
18
19 return result
20
21# Example usage:
22s = "banana"
23solution = Solution()
24print(solution.longestDupSubstring(s))
This Python solution generates and sorts the suffix array, then finds the longest common prefix of each consecutive suffix by comparing characters, revealing the longest repeated substring.