Leetcode#30 Substring with Concatenation of All Words

原题地址

 

将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 }

 

posted @ 2015-01-22 18:23  李舜阳  阅读(899)  评论(0编辑  收藏  举报