原题链接:力扣
描述:
给你一个字符串 s ,考虑其所有 重复子串 :即,s 的连续子串,在 s 中出现 2 次或更多次。这些出现之间可能存在重叠。
返回 任意一个 具有最长长度的重复子串。如果 s 不含重复子串,那么答案为 "" 。
示例 1:
输入:s = "banana"
输出:"ana"
示例 2:
输入:s = "abcd"
输出:""
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-duplicate-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
第一种思路:集合额方案。
首先,如果字符串重复,那么他们的首字符一定是相同的。
然后构建一个map,key为字符串,value为字符串对应的位置的集合。
所以遍历一遍字符串,获取每个字符串,如果字符串存在则依次判断集合中作为起始位的字符串是否和当前字符串重复。
判断字符串是否重复的话,不用完全判断每一个字符。比如abce,abcd,此时的最大重复字符串为3的话,那么就直接判断0,0+4和n,n+4长度是否相同即可。
第二种思路:滑动窗口的方案。
构建一个区间,开始位置为i,结束为止为j。
然后开始遍历,一开始i和j相同,如果重复,这时候最大的长度为1,继续遍历。
下一个字符串如果重复的话,那么就j++,判断更大长度的是否重复。
如果不重复,则i++并且j++。一样判断maxLength+1长度的是否重复。
至于如何判断重复,我这里采取的是
s.indexOf(curStr, i + 1) <= i
的方案,这样的效率会稍微高一些。每次不用全局搜索。
第三种思路:二分查找方案
我们判断长度为N的字符串是否存在重复,那么我们可以这样做,依次取(0,0+N),(1,1+N),(2,2+N)...长度的字符串,把字符串添加到map当中。这样如果字符串存在重复,那么map中一定存在。
所以依据这个理论,我们可以运行二分查找的理论,给的字符串长度为length的话,先判断N=length/2长度的是否存在,如果存在则判断N=length/2+length/4长的,反之则判断N=length/4长度的字符串是否存在。这样我们就可以知道最长重复的字符串了。
由于本地的字符串很长,length很大,所以如果把每个字符串都加到map中的话,内存消耗很大。所以我们要想一个办法来匹配唯一的字符串,即key代表唯一字符串。
官方题解的方案是取模。如果不取模,简单的把这些字符串做一个累加,key为累加值,value为一个链表,如果key相同,则value遍历,和hashMap的结构一样,其实也可以的。
代码:
第一种方案:O(n2)复杂度,java环境会超时
public String longestDupSubstring(String s) {
int num = 0;
Map<String, List<Integer>> map = new HashMap<>();
String maxStr = "";
int maxLength = 0;
List<Model> list = new ArrayList<>();
Set<Integer> set = new HashSet<>();
for (int i = 0; i < s.length(); i++) {
String item = s.substring(i, i + 1);
//新节点加入list
set.clear();
List<Integer> indexList = map.computeIfAbsent(item, f -> new ArrayList<>());
//遍历list,不符合的移除
Iterator<Model> iterator = list.iterator();
while (iterator.hasNext()) {
num++;
Model next = iterator.next();
String substring = s.substring(next.startIndex + next.length, next.startIndex + next.length + 1);
if (item.equals(substring)) {
next.length++;
if (next.length > maxLength) {
maxLength = next.length;
maxStr = s.substring(next.startIndex, next.startIndex + next.length);
}
set.add(next.startIndex + next.length);
} else {
iterator.remove();
}
}
for (Integer index : indexList) {
if (!set.contains(index + 1)) {
Model model = new Model();
model.startIndex = index;
model.str = item;
model.length = 1;
list.add(model);
set.add(model.startIndex + model.length);
}
if (maxLength == 0) {
maxLength = 1;
maxStr = item;
}
}
indexList.add(i);
}
System.out.println("num:" + num);
return maxStr;
}
static class Model {
int startIndex = 0;
int length = 0;
String str = "";
}
第二种方案:O(n2)复杂度,java环境会超时
/**
* 动态区间的方案
* @param s
* @return
*/
public String longestDupSubstring(String s) {
String maxStr = "";
String curStr = "";//滑动窗口
int num = 0;
//复杂度:n2
for (int i = 0, j = 0; i < s.length(); i++) {
if (j == s.length() - 1) {
break;
}
while (j < s.length()) {
curStr = s.substring(i, j + 1);
j++;
num++;
//如果匹配的字符串长度较多,这个比较合适,indexOf的效率高
if (s.indexOf(curStr, i + 1) <= i) {
break;
}
if (curStr.length() > maxStr.length()) {
maxStr = curStr;
}
}
}
System.out.println(num);
return maxStr;
}
第三种方案:O(n*lng(n))复杂度,