题目地址:
https://leetcode.com/problems/longest-repeating-substring/
给定一个长 n n n字符串 s s s,求其最长重复子串的长度。
思路是二分 + 字符串哈希。二分答案,答案的范围是 [ 1 , n − 1 ] [1,n-1] [1,n−1],而判断 s s s是否含一个长 k k k的重复子串是容易的,只需看一下所有长 k k k子串的哈希值是否有重复出现的即可,这可以用Rolling Hash的技巧。代码如下:
class Solution {
public:
using UL = unsigned long;
int longestRepeatingSubstring(string s) {
int n = s.size(), l = 1, r = n - 1;
if (l > r) return 0;
UL P = 131;
auto check = [&](int len) {
unordered_set<UL> st;
UL pow = 1, ha = 0;
for (int i = 0; i < len; i++) {
pow = pow * P;
ha = ha * P + s[i];
}
st.insert(ha);
for (int i = len; i < n; i++) {
ha = ha * P + s[i];
ha -= pow * s[i - len];
if (st.count(ha)) return true;
st.insert(ha);
}
return false;
};
while (l < r) {
int mid = l + (r - l + 1 >> 1);
if (check(mid))
l = mid;
else
r = mid - 1;
}
return check(l) ? l : 0;
}
};
时间复杂度 O ( n log n ) O(n\log n) O(nlogn),空间 O ( n ) O(n) O(n)。