You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.
For example, given:
s: "barfoothefoobarman"
words: ["foo", "bar"]
You should return the indices: [0,9]
.
(order does not matter).
思路:使用两个指针left和right维护一个窗口,left是窗口左边开始的位置,right是窗口右边的位置。使用dicMap作为一个字典,这个字典里面只存放在s中连续,且在words中存在的词汇。
如果没有形成窗口,那么left不变,right向后滑动。如果已经形成一个窗口,那么left和right就不断向后滑动,维持一个窗口,同时维持dicMap里面的元素。count==0代表dicMap字典里的元素和words相等。
Runtime: 22 ms beats 99.77% of java submissions.
public static List<Integer> findSubstring(String s, String[] words) {
List<Integer> res = new ArrayList<>();
int sLen = s.length(), wordLen = words[0].length(), windowLen = wordLen * words.length;
HashMap<String, Integer> map = new HashMap<>();
for (String word : words) map.put(word, map.getOrDefault(word, 0) + 1);
for (int i = 0; i < wordLen; i++) { // Run wordLen scans
HashMap<String, Integer> dicMap = new HashMap<>();//作为一个字典
for (int right = i, left = i, count = 0; right + wordLen <= sLen; right += wordLen) {
if (left + windowLen > sLen) break;
String word = s.substring(right, right + wordLen);
if (!map.containsKey(word)) {
dicMap.clear();
count = 0;
left = right + wordLen;
} else {
if (right - left == windowLen) { // Remove previous word of current window
String preWord = s.substring(left, left + wordLen);// previous word
left += wordLen;//left是窗口左边开始的位置,right是窗口右边的位置
if (preWord.equals(word)) {
if (count == 0) res.add(left);//res has contained left-wordLen
continue;
}
int val = dicMap.get(preWord);
dicMap.put(preWord, val - 1);
if(val-1>=map.get(preWord)) count--;//Reduce count of exceeded word
}
dicMap.put(word, dicMap.getOrDefault(word, 0) + 1);//word放入字典中
if (dicMap.get(word) > map.get(word))
count++; //More than expected, increase count
if (count == 0 && left + windowLen == right + wordLen) {
res.add(left);//if current window valid
}
}
}
}
return res;
}