标签:
将L中的单词看成一个整体,这道题与Minimun Window String比较类似,都是利用滑动窗口搜索。
所以,依次枚举所有S的起始位置i,从i处开始搜索。当然并不需要枚举所有的i,i最多等于L中单词长度-1。比如L中的单词长度为3,那么当枚举过i=0,1,2后,不用再尝试i=3了,因为结果已经被i=0的情况覆盖过了。
用左右两个指针(left,right)分别指向窗口的左右边界,按如下规则移动指针:
1. 拓展窗口。不妨设right指向的单词是w,观察w:
如果w不在L中,重置窗口,让窗口跨过w,即right++, left = right
否则,不妨设w在窗口中出现的次数是window[w],w在L中出现的次数为traits[w]。
如果window[w] < traits[w],说明这个单词还不够呢,那么拓展窗口,将right右移一个单位,别忘了window[w]++
如果window[w] == traits[w],说明当前窗口可能构成了一组解,那么停止扩展窗口,跳至第3步(检查)。
如果window[w] > traits[w],说明w出现次数太多了,不能都放在窗口里,那么停止扩展窗口,跳至第2步(收缩窗口),目的是把多余的w排出窗口。
2. 收缩窗口。第1步保证了此时遇到的单词一定都是出现在L中的。
走到这里说明一定是哪个单词多了,不妨假设就是w,那么不断右移left收缩窗口,每次window[*left]--,直到window[w] == traits[w],结束收缩
3. 检查是否是一组解
这一步很简单,看一下窗口长度是否等于L的长度和即可,因为前面两步保证了任意单词w一定出现在L中,并且window[w] <= traits[w]。如果是解,加入结果集中。
之后返回第1步,继续下一个轮回,直到窗口移动到S右边界。
代码:
1 vector<int> findSubstring(string S, vector<string> &L) { 2 vector<int> res; 3 map<string, int> traits; 4 5 if (L.empty() || S.empty()) return res; 6 7 for (auto s : L) 8 traits[s]++; 9 int len = L[0].length(); 10 11 for (int i = 0; i < len; i++) { 12 map<string, int> window; 13 14 int l = i; 15 int r = i; 16 while (r < S.length()) { 17 while (r < S.length()) { 18 string word = S.substr(r, len); 19 r += len; 20 if (traits.find(word) == traits.end()) { 21 window.clear(); 22 l = r; 23 } 24 else { 25 window[word]++; 26 if (window[word] >= traits[word]) 27 break; 28 } 29 } 30 while (l < r) { 31 string head = S.substr(l, len); 32 string tail = S.substr(r - len, len); 33 if (window[tail] == traits[tail]) 34 break; 35 l += len; 36 window[head]--; 37 } 38 if (r - l == len * L.size()) { 39 res.push_back(l); 40 } 41 } 42 } 43 44 return res; 45 }
Leetcode#30 Substring with Concatenation of All Words
标签:
原文地址:http://www.cnblogs.com/boring09/p/4242416.html