Q:给出一个字符串 S,考虑其所有重复子串(S 的连续子串,出现两次或多次,可能会有重叠)。返回任何具有最长可能长度的重复子串。(如果 S 不含重复子串,那么答案为 ""。)
示例 1:
输入:"banana"
输出:"ana"
示例 2:
输入:"abcd"
输出:""
提示:
2 <= S.length <= 10^5
S 由小写英文字母组成。
通过次数1,383提交次数7,906
A:
1.字符串编码法:具体可以去看Rabin-Karp 字符串编码
代码:
public String longestDupSubstring(String S) {
int len = S.length();
int a = 26;
if (len <= 1)
return "";
int[] nums = new int[len];
for (int i = 0; i < len; i++) {
nums[i] = S.charAt(i) - 'a';
}
for (int i = len - 1; i > 0; i--) {
//i是子串长度
HashMap<Long, Integer> map = new HashMap<>();
long tmp = 0;
long aL = 1;
//算第一个hashcode
for (int j = 0; j < i; j++) {
tmp = (tmp * a + nums[j]) % MOD;
aL = aL * a;
}
map.put(tmp, 0);
for (int j = 1; j <= len - i; j++) {
tmp = (tmp * a - nums[j - 1] * aL % MOD + nums[j + i - 1]) % MOD;
if (map.containsKey(tmp)) {//这里做了一个判断,因为哈希表毕竟是有可能冲突的。但我没想好冲突发生怎么解决
String sub = S.substring(j, j + i);
String sub2 = S.substring(map.get(tmp), map.get(tmp) + i);
if (sub.equals(sub2))
return sub;
}
map.put(tmp, j);
}
}
return "";
}
但……超出时间限制了。
2.二分查找+字符串编码法
public String longestDupSubstring(String S) {
int len = S.length();
int a = 26; // 26进制
long module = (long) Math.pow(2, 32); // 取一个足够大的数,用以取模
if(len <= 1)
return "";
int[] nums = new int[len];
for(int i = 0; i < len; i++){
nums[i] = (int) S.charAt(i) - (int) 'a'; // 只考虑小写字母
}
int low = 1;
int high = len;
while(low != high) {
int L = (high-low)/2 + low;
if(search(L, a, module, nums) != -1)
low = L + 1;
else
high = L;
}
int start = search(low-1, a, module, nums);
if(start == -1)
return "";
else
return S.substring(start, start+low-1);
}
// 返回重复字符串的起始位置
// 参数:L-重复字符串的长度,a-进制,module-取模数,nums-字符串的编码数组
public int search(int L, int a, long module, int[] nums) {
int len = nums.length;
HashSet<Long> hashSet = new HashSet<Long>();
long tmp = 0;
long aL = 1;
for(int j = 0; j < L; j++){
tmp = (tmp *a + nums[j]) % module; // 防止溢出
//System.out.println(tmp);
aL = (aL*a) % module;
}
hashSet.add(tmp);
for(int j = 1; j <= len - L; j++){ // 长度为i的窗口
tmp = (tmp*a - nums[j-1]*aL%module + module) % module; // 去掉前一位
tmp = (tmp + nums[j+L-1]) % module;
if(hashSet.contains(tmp))
return j;
hashSet.add(tmp);
}
return -1;
}
3.还有后缀树法,等有时间做