Description
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.
Example
For example, given: s: "barfoothefoobarman" words: ["foo", "bar"] You should return the indices: [0,9]. (order does not matter).
thinking
- It hurts me to do this. When doing this, we always consider optimization and optimization. When submitting, we found that there are too many special cases. Optimize the fart. Optimize half a day or more than 800 ms.
- Do not write your own specific ideas, paste a code out
- Move a big man's code online. Alas.
Code
class Solution { public: vector<int> findSubstring(string s, vector<string>& words) { vector<int> res; if (s.empty() || words.empty()) return res; unordered_map<string, int> hashMap; unordered_map<string, int> copyMap; unordered_map<string, int> cmpMap; int len = words[0].size(), sumLen = 0; for (int i = 0; i < words.size(); ++i){ hashMap[words[i]]++; cmpMap[words[i]] = 0; sumLen += words[i].size(); } copyMap = hashMap; int i = 0, sum = 0; string tmp; int flag = 1, curLen = 0, start = 0; while (i < s.size()){ sum = 0; tmp = s.substr(i, len); if (copyMap.find(tmp) == copyMap.end()){ start++; flag++; curLen = 0; hashMap = copyMap; i = start; } else{ if (cmpMap[tmp] == flag){ if (hashMap[tmp] == 0){ hashMap = copyMap; start++; curLen = 0; ++flag; i = start; } else{ hashMap[tmp]--; curLen += len; i += len; } } else{ cmpMap[tmp] = flag; hashMap[tmp]--; curLen += len; i += len; } } if (curLen == sumLen){ res.push_back(start); start++; curLen = 0; flag++; i = start; hashMap = copyMap; } } return res; } };
-
Analysis of a Big Man's Code
class Solution { public: vector<int> findSubstring(string s, vector<string>& words) { vector<int> res; if (s.empty() || words.empty() || s.size() < words[0].size()) return res; //One is used to save the original dictionary, and the other is used to assist. unordered_map<string, int> hashMap; unordered_map<string, int> cmpMap; int num = words.size(); int len = words[0].size(); for (int i = 0; i < num; ++i){ hashMap[words[i]]++; } int count = 0, start = 0; string tmp; //There is no need to traverse the past from 0 - s.size(), one by one. In fact, it is only possible to start with 0-len. This is a key point and can be pushed forward. for (int i = 0; i < len; ++i){ count = 0; //Reset start and map start = i; cmpMap.clear(); //Compare one word at a time, not one character at a time. for (int j = i; j <= s.size() - len; j += len){ tmp = s.substr(j, len); //On the inside if (hashMap.find(tmp) != hashMap.end()){ cmpMap[tmp]++; //The current word may be in the result if (cmpMap[tmp] <= hashMap[tmp]) count++; else{ //The current word has been repeated //start and subtract from the top. while (cmpMap[tmp] > hashMap[tmp]){ string strTemp = s.substr(start, len); cmpMap[strTemp]--; if (cmpMap[strTemp] < hashMap[strTemp]) count--; start += len; } } //Save results if (count == num){ res.push_back(start); cmpMap[s.substr(start, len)]--; start += len; count--; } } else{ //Not in the dictionary, start over cmpMap.clear(); start = j + len; count = 0; } } } return res; } };
Big man's code has learned a lot, but now there is no time for analysis.