Binary search + Rabin-Karp
Time O(n log n) expected Space O(n)find(len) slides a hash over s, storing start positions per hash, and returns a substring whose hash and characters match an earlier one.
s = "banana"search(vars)
Step 1/4The answer's length is between 1 and 5. Try the middle, 3.
import java.util.*;
class Solution {
public String longestDupSubstring(String s) {
int lo = 1, hi = s.length() - 1;
String best = "";
while (lo <= hi) {
int mid = (lo + hi) >>> 1;
String dup = find(s, mid);
if (dup != null) { best = dup; lo = mid + 1; } else hi = mid - 1;
}
return best;
}
private String find(String s, int len) {
long MOD = 1_000_000_007L, B = 131, pow = 1, h = 0;
for (int i = 0; i < len; i++) pow = pow * B % MOD;
Map<Long, List<Integer>> seen = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
h = (h * B + s.charAt(i)) % MOD;
if (i >= len) h = ((h - s.charAt(i - len) * pow) % MOD + MOD) % MOD;
if (i < len - 1) continue;
int start = i - len + 1;
List<Integer> starts = seen.computeIfAbsent(h, k -> new ArrayList<>());
for (int j : starts) if (s.regionMatches(j, s, start, len)) return s.substring(start, start + len);
starts.add(start);
}
return null;
}
}Verdict: A suffix array solves it in O(n log n) deterministically, but this is far easier to write.