LC30 Substring with Concatenation of All Words
这题和LC76 Minimum Window Substring可以归为一类,就是给出要找的字符(字符串)和相应个数,利用滑动窗口在另一个字符串上找。类似的题目还有LC3。
首先需要用map把出现的单词和相应出现的次数记录下来。
然后维护一个窗口,一步步往前移动。每移动一次就检查是否满足条件。解题时注意每个单词的长度是固定的,这一点给解题带来很大方便。
1 class Solution{ 2 public: 3 vector<int> findSubstring(string S, vector<string> &L) { 4 map<string,int> words; 5 map<string,int> cur; 6 int wordNum = L.size(); 7 for(int i = 0; i < wordNum; i++) 8 words[L[i]]++; 9 int wordLen = L[0].size(); 10 vector<int> res; 11 for(int i = 0; i <= (int)S.size()-wordLen*wordNum; i++) 12 { 13 cur.clear(); 14 int j; 15 for(j = 0; j < wordNum; j++) 16 { 17 string word = S.substr(i+j*wordLen, wordLen); 18 if(words.find(word) == words.end()) 19 break; 20 cur[word]++; 21 if(cur[word]>words[word]) 22 break; 23 } 24 if(j == wordNum) 25 res.push_back(i); 26 } 27 return res; 28 } 29 };
以上程序需要维护两个map,其中一个用于循环后复原初始map。这造成了空间上的浪费。此外,移动一次仅仅移动一步,这对效率而言也是损害。
其实,移动可以分为两种,一种是开始坐标的移动,这种移动每次移动1步,但最多只需移动一个单词长度即可。另一种移动则按单词长度来移动。这样维护的窗口能更有效地找到结果,具体思路和LC76 Minimum Window Substring 类似。
小细节需要注意的是,对于map容器,以下代码:
1 if(imap.find("u")==imap.end()) 2 imap.insert(make_pair("u",1)); 3 else 4 imap["u"]++;
可以直接用一句话(效率更高)代替
imap["u"]++;
如果"u"一开始不存在,imap["u"]会初始化为0。
另外unordered_map比map查询速度要快。
1 class Solution { 2 public: 3 vector<int> findSubstring(string s, vector<string>& words) { 4 vector<int> result; 5 if (words.size() == 0) { 6 return result; 7 } 8 unordered_map<string, int> hash; 9 for (int i = 0; i < words.size(); i++) { 10 hash[words[i]]++; 11 } 12 int wSize = words[0].length(); 13 for (int start = 0; start < wSize; start++) { 14 int wCount = 0; 15 unordered_map<string, int> slidingWindow; 16 for (int i = start; i + wSize <= s.length(); i+=wSize) { 17 string word = s.substr(i, wSize); 18 if (hash.find(word) == hash.end()) { 19 slidingWindow.clear(); 20 wCount = 0; 21 } else { 22 wCount++; 23 slidingWindow[word]++; 24 while (hash[word] < slidingWindow[word]) { 25 string removedWord = s.substr(i - (wCount-1) * wSize, wSize); 26 slidingWindow[removedWord]--; 27 wCount--; 28 } 29 } 30 if (wCount == words.size()) { 31 result.push_back(i - (wCount - 1) * wSize); 32 } 33 } 34 } 35 return result; 36 } 37 };
(用哈希数组记录单词出现次数,别想着以后碰到了单词可以将对应值减1,然后到了一定时候用取巧的方法判断数组是否都为0 。换言之,貌似除了循环,没有什么取巧的函数可以判断一个整型数组是否都为0)