刷了LeetCode30道题了,这道题是最难通过的,测试数据很刁钻,各种超时和边界考虑不周。参考了很多解法,中文的就没有不超时又解释明白的。以下是我的带注释代码。想看懂必须得先会Longest Substring Without Repeating Characters后两种解法。
public class Solution{
public List<Integer> findSubstring(String s, String[] words){
List<Integer> res = new LinkedList<>();
Map<String, Integer> dict = new HashMap<>(), window = new HashMap<>();
if(s == null || words == null || s.length() == 0 || words.length == 0){ return res; }
//建立字典
for(String word : words){dict.put(word, dict.containsKey(word) ? dict.get(word) + 1 : 1);}
int K = words[0].length(), L = s.length(), count = 0;
//举例,s:"abcdefghi" words[]:{"bc","de"}
// K=2,一共遍历两次
//第一次:ab cd ef gh
//第二次:bc de fg hi
for(int i = 0; i < K; i++){
//遍历前初始化
count = 0;
window.clear();
for(int left = i, right = i; right <= L - K; right += K){
String word = s.substring(right, right + K);
if(dict.containsKey(word)){
//只要字典里有该新单词,就把新单词加到窗口中。
window.put(word, window.containsKey(word) ? window.get(word) + 1 : 1);
count++;
//新单词在当前窗口中不合法:使窗口中该单词数量超标。移动窗口左指针到该单词的下一个单词。
if(window.get(word) > dict.get(word)){
while(window.get(word) > dict.get(word)){
String temp = s.substring(left, left + K);
window.put(temp, window.get(temp) - 1);
count--;
left += K;
}
}
//新加的单词在该窗口中合法,并且窗口中单词数量满足要求。此时将窗口左指针添加到结果容器并移动窗口左指针到下一个单词。
else if(count == words.length){
res.add(left);
String temp = s.substring(left, left + K);
window.put(temp, window.get(temp) - 1);
count--;
left += K;
}
}
//字典里没有该新单词:当前窗口全部废掉。移动窗口左指针到窗口右指针的下一个单词。
else{
count = 0;
window.clear();
left = right + K;
}
}
}
return res;
}
}