用sliding window來優化這個遍歷過程。保證sliding window裏面的單詞都是候選詞向量裏面的詞,而且每個候選詞只能出現一次。這樣的話當sliding window裏面的大小與候選詞向量的單詞數相等的時候,就說明sliding window就是一種合理的答案。用一個哈希表記錄候選詞向量裏每個詞的個數,在遍歷原字符串的時候,如果下一個單詞是在候選詞向量裏面的,而且在sliding window裏面出現的次數沒有超過哈希表記錄的次數,就可以擴大這個sliding window,這種是最理想的情況,一直增大sliding window,直到這個sliding window的大小等於候選詞的數量,就把這時候的start index記錄下來。但是事情不會總是這麼完美的,當遇到不是候選詞的單詞,說明sliding window的start index不是一種合理答案,就要清空這個sliding window並且將sliding window的start index向右移一位;還有一種情況是跟單詞的次數有關的,當遇到一個候選詞w,但是sliding window裏面的w出現的次數已經超過了哈希表記錄的次數,說明這時的sliding window不是一種合理答案,不能繼續擴大sliding window,但這時候是不是和上面的這種情況一樣,直接清空sliding window,並右移start index呢?如果將這兩種情況合在一起考慮的話,就跟最樸素的查找是一樣的了。
這裏利用sliding window,每一次遍歷都要考慮到直到原字符串最後一個字符的所有的情況。所以startInd = 0和startInd = wordLen的分詞結果是相同的,startInd = wordLen裏所有的合理情況在startInd = 0已經被涵蓋了。所以外循環的大小隻是wordLen - 1。這樣的話,當遇到一個候選詞w,但是sliding window裏面的w出現的次數已經超過了哈希表記錄的次數,說明startInd已經不可能是一種合理答案了,但是startInd + x * wordLen還有可能是一種合理答案,這時候要把sliding window的左邊界往右移,縮小sliding window的大小。
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
if (words.size() == 0 || s == "") {
return {};
}
vector<int> resultVec;
unordered_map<string, int> hashTable;
for (int i = 0; i < words.size(); i++) {
if (hashTable.find(words[i]) == hashTable.end()) {
hashTable[words[i]] = 0;
}
hashTable[words[i]]++;
}
int wordLen = int(words[0].length()), wordCount = 0, vectorSize = int(words.size());
unordered_map<string, int> counterTable;
for (int i = 0; i < wordLen; i++) {
int startInd = i;
counterTable.clear();
wordCount = 0;
for (int j = startInd; j < s.length(); j += wordLen) {
string checkStr = s.substr(j, wordLen);
if (hashTable.find(checkStr) == hashTable.end()) {
counterTable.clear();
wordCount = 0;
continue;
} else {
if (counterTable.find(checkStr) == counterTable.end()) {
counterTable[checkStr] = 0;
}
counterTable[checkStr]++;
wordCount++;
while (counterTable[checkStr] > hashTable[checkStr]) {
string startSub = s.substr(j - (wordCount - 1) * wordLen, wordLen);
counterTable[startSub]--;
wordCount--;
if (counterTable[startSub] == 0) {
counterTable.erase(startSub);
}
}
if (wordCount == vectorSize) {
resultVec.push_back(j - (wordCount - 1) * wordLen);
}
}
}
}
return resultVec;
}
};