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.還有后綴樹法,等有時間做
