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).
class Solution {
public:
std::vector<int> findSubstring(std::string S, std::vector<std::string> &L) {
std::vector<int> res;
if (L.size()==0) return res;
if (S.size() < L.size()*L[0].size()) return res;
int wl = L[0].size();
std::unordered_map<std::string, std::vector<int> > hashLocation;
std::unordered_map<std::string, std::vector<int> >::iterator hashIt;
std::unordered_map<std::string, int> hashIndex;
std::vector<int> empty;
for (int i=0; i<wl; ++i) {
hashLocation.clear();
for (int k=0; k<L.size(); ++k) {
if (hashLocation.find(L[k]) == hashLocation.end()) {
hashLocation[L[k]] = empty;
}
hashLocation[L[k]].push_back(-1);
hashIndex[L[k]] = 0;
}
int head=i, curr=i, hitCnt=0;
while (curr<S.size()) {
std::string a = S.substr(curr, wl);
hashIt = hashLocation.find(a);
if (hashIt==hashLocation.end()) {
head = curr+wl;
curr = head;
hitCnt = 0;
continue;
}
int earliestCur = hashIt->second[hashIndex[a]];
if (earliestCur < head) {
hitCnt++;
if (hitCnt == L.size()) {
res.push_back(head);
head += wl;
hitCnt--;
}
} else {
hitCnt -= (earliestCur-head)/wl;
head = earliestCur+wl;
}
hashIt->second[hashIndex[a]] = curr;
hashIndex[a] = (hashIndex[a]+1)%hashIt->second.size();
curr += wl;
}
}
return res;
}
};