微软面试题: LeetCode 76. 最小覆盖子串 出现次数:2

题目描述:

 

 题解:

   滑动窗口思想:用 i, j 表示滑动窗口的左边界和右边界,通过改变i,j来扩展和收缩滑动窗口,可以想象成一个窗口在字符串上游走,

当这个窗口包含的元素满足条件,即包含字符串T的所有元素,记录下这个滑动窗口的长度j-i+1 和 窗口其实位置 i ,这些长度中的最小值

对应的子串 就是要求的结果。设置一个变量 cnt 记录 滑动窗口中

   扩展滑动窗口 :向右 右边界移动  j 直到 窗口中的子串恰好覆盖 t 中所有字符时停止。(从不覆盖到覆盖)

   收缩滑动窗口: 向右移动左边界   i 直到 窗口中的子串恰好覆盖 t 中所有字符时停止。(再移动一步就不再覆盖,此时保存最小子串)

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 class Solution {
 4 public:
 5     string minWindow(string s, string t)
 6     {
 7         unordered_map<char,int> need;//记录 字符串t中的字符和出现的次数 
 8         unordered_map<char,int> window;// 记录滑动窗口内的字符和出现的次数
 9         for(int i = 0; i < t.size();++i)
10         {
11             need[t[i]]++;
12         }
13         const int t_cnt = need.size();
14         int start = 0;//s中包含t中所有字符的最短子串起始下标
15         int len = INT_MAX;//最短子串长度
16         int cnt = 0;//t中的字符 在滑动窗口中已完备存在的个数
17         int left = 0,right = 0;//滑动窗口左右边界
18         char c = ' ';
19         while (right < s.size())
20         {
21             //移动 right 扩大窗口,到窗口中的子串恰好覆盖 t 中所有字符时停止
22             while (cnt < t_cnt && right < s.size())
23             {
24                 c = s[right];
25                 if(need.find(c) != need.end())
26                 {
27                     if(++window[c] == need[c])
28                     {
29                         ++cnt;
30                     }
31                 }
32                 ++right;
33             }
34             //right 移动到最右,滑动窗口内的子串仍然没有覆盖t中所有字符,直接返回之前得到的最小覆盖子串
35             if(right == s.size() && cnt < t_cnt) 
36             {
37                 return len == INT_MAX?"":s.substr(start,len);
38             }
39             //移动left,收缩窗口,到窗口内的子串恰好覆盖 t 中所有字符时停止(再收缩一步就不再覆盖了)
40             while(left < right && cnt == t_cnt)
41             {
42                 c = s[left];
43                 if(need.find(c) != need.end())
44                 {
45                     if(window[c]-- == need[c])
46                     {
47                         --cnt;
48                     }
49                 }
50                 ++left;
51             }
52             //此时的最小覆盖子串的范围应该是 [left-1,right-1]
53             if(right - left + 1 < len )
54             {
55                 start = left - 1;
56                 len = right - left + 1;
57             }
58         }
59         return len == INT_MAX?"":s.substr(start,len);
60     }
61         
62 };

 

posted @ 2021-04-09 15:06  谁在写西加加  阅读(55)  评论(0编辑  收藏  举报