You are given a string, S, and a list of words, L, that are all of the same length. Find all starting indices of substring(s) in S that is a concatenation of each word in L exactly once and without any intervening characters.
For example, given:
S: "barfoothefoobarman"
L: ["foo", "bar"]
You should return the indices: [0,9]. (order does not matter).
The idea is similar to longest substring without repeat chars, use a map to track used words, if the all used word are removed from the map, we found an answer.
public List<Integer> findSubstring(String S, String[] L) {
List<Integer> results = new ArrayList<Integer>();
if (S==null||L==null||L.length==0) {
return results;
}
int wordLength = L[0].length();
int length = L.length;
if (S.length()<length*wordLength) {
return results;
}
Map<String, Integer> wordCount = new HashMap<String, Integer>();
Map<String, Integer> wordFind = new HashMap<String, Integer>();
for (String str : L) {
if (wordCount.get(str)==null) {
wordCount.put(str, 1);
} else {
wordCount.put(str, wordCount.get(str)+1);
}
}
int index=0;
// need <= because "aaa" "a" and "a" 1 <= (3-2) we need to calculate on index=1 too
while (index<=S.length()-wordLength*length) {
wordFind.clear();
wordFind.putAll(wordCount);
String subStr = S.substring(index, index+wordLength*length);
while(!subStr.isEmpty()) {
String word = subStr.substring(0, wordLength);
if (wordFind.containsKey(word)) {
wordFind.put(word, wordFind.get(word)-1);
if (wordFind.get(word)==0) {
wordFind.remove(word);
}
//no consecutive match, break the inner loop;
} else {
break;
}
subStr = subStr.substring(wordLength, subStr.length());
}
if (wordFind.isEmpty()) {
results.add(index);
}
index++;
}
return results;
}