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).
这题很有意思,时间复杂度可以做到O(N)
public ArrayList<Integer> findSubstring(String S, String[] L) {
ArrayList<Integer> result = new ArrayList<Integer>();
if (S == null || L == null || L.length == 0) {
return result;
}
int m = S.length();
int n = L[0].length();
Map<String, Integer> timesMap = new HashMap<String, Integer>();
for (String s : L) {
Integer times = timesMap.get(s);
if (times == null) {
times = 0;
}
times++;
timesMap.put(s, times);
}
Map<String, LinkedList<Integer>> matchMap = new HashMap<String, LinkedList<Integer>>();
int i = 0;
int matchCount = 0;//已经匹配的数量
while (i < n) {
int j = i;
int begin = j;
while (j + n <= m) {
String s = S.substring(j, j + n);
Integer times = timesMap.get(s);
if (times != null) {
LinkedList<Integer> matchIdxs = matchMap.get(s);
if (matchIdxs == null) {
matchIdxs = new LinkedList<Integer>();
matchMap.put(s, matchIdxs);
}
if (matchIdxs.size() < times) { //尚未完全匹配
matchIdxs.addLast(j);
j += n;
matchCount++;
if (matchCount == L.length) {// find a result
result.add(begin);
String ss = S.substring(begin, begin + n);//remove the first match
LinkedList<Integer> firstMatch = matchMap.get(ss);
firstMatch.removeFirst();
matchCount--;
//move on to find next
begin += n;
}
} else {// 已经匹配
Integer firstMatchIndex = matchIdxs.getFirst();
// remove the match before matchIdx
Iterator<Map.Entry<String, LinkedList<Integer>>> it = matchMap
.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, LinkedList<Integer>> entry = it.next();
LinkedList<Integer> mList = entry.getValue();
while(!mList.isEmpty() && mList.getFirst() <= firstMatchIndex) {
mList.removeFirst();
matchCount--;
}
}
begin = firstMatchIndex + n;// update begin
matchIdxs.addLast(j);
matchCount++;
j += n;
}
} else {
j += n;
begin = j;
//clear match result
Iterator<Map.Entry<String, LinkedList<Integer>>> it = matchMap
.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, LinkedList<Integer>> entry = it.next();
LinkedList<Integer> mList = entry.getValue();
mList.clear();
}
matchCount = 0;
}
}
//clear match result
Iterator<Map.Entry<String, LinkedList<Integer>>> it = matchMap
.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, LinkedList<Integer>> entry = it.next();
LinkedList<Integer> mList = entry.getValue();
mList.clear();
}
matchCount = 0;
i++;
}
return result;
}