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 }

 

你可能感兴趣的:(substring)