leetcode76.最小覆盖子串

给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。

示例:

输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"

说明:

  • 如果 S 中不存这样的子串,则返回空字符串 “”。
  • 如果 S 中存在这样的子串,我们保证它是唯一的答案。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-window-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

完整代码

参考:滑动窗口
基本思想
滑动窗口:
ps:刚开始想到了用滑动窗口的思想,但是不知道该如何更新两个指针,下面重点说明该如何更新两个指针

  • 初始时,用两个指针来指示滑动窗口,滑动窗口的大小为0,两个指针都指向字符串s的起始位置
  • 循环条件:右指针移动到字符串s的尾部时,循环结束
  • 如何更新右指针:当窗口内不存在题目要求的子串t时,更新右指针,增大窗口
  • 如何更新左指针:当窗口内存在题目要求的子串时,更新左指针,缩小窗口

该题目还有十分关键的一点:如何判断窗口内的字符串是否已经覆盖了题目要求的子串?

  • 刚开始时,定义了两个map,每次都统计窗口内每个字符的个数,然后再和待覆盖子串进行对比,这种思路能够通过大部分测试用例,剩下最后两个由于超出时间限制无法ac.
  • 另一种思路:也是参考了一部分别人的思想进行优化
    对于窗口子串,在右指针移动的同时,统计字符出现的次数,左指针移动时,递减次数,这个好处理。
    那如何判断是否覆盖呢?
    依然是在左右指针移动的过程中进行统计,右指针移动时,如果当前字符在待覆盖子串中,且恰好和待覆盖子串中的数目相等,将匹配的个数+1(注意:这里只有相等时才+1,如果出现大于的情况,其实已经在相等的时候统计了,避免重复统计);左指针移动时,如果递减后恰好使得数目不满足要求,则-1
class Solution {
public:
    string minWindow(string s, string t) {
        string res = "";
        if(s.size() < t.size())
            return res;
        int left = 0, right = 0;
        int res_s = s.size(), res_e = INT_MAX;
        //将res_s初始化成s.size()是因为当不包含子串的时候,截取的结果串为空
        //将res_e初始化成最大值的目的是:遇到第一个结果串时能正确保存结果
        
        //将字符串T映射成map
        map<char,int> m, cur;
        int i, match = 0;//match记录s中有几个字符已经符合t的要求了
        for(int i = 0; i < t.size(); ++i){
            ++m[t[i]];
        }
        //统计第一个字符
        ++cur[s[right]];
        if(m.count(s[right]) && cur[s[right]] == m[s[right]])
            ++match;
        while(right < s.size()){
            //cur.clear();
            //if(right - left >= t.size() - 1){
                // for(i = left; i <= right; ++i){
                //     ++cur[s[i]];
                // }
                // for(i = 0; i < t.size(); ++i){
                //     if(cur[t[i]] < m[t[i]])
                //         break;
                // }
                if(match == m.size()){//包含t中的所有字母
                    if(right - left < res_e - res_s){//新窗口比原窗口小
                        res_s = left;
                        res_e = right;
                    } 
                    if(m.count(s[left]) && cur[s[left]] == m[s[left]])
                        --match;
                    --cur[s[left]];
                    
                    ++left;//缩小窗口
                    
                    
                } 
                // else{//不包含
                //     ++right;//向右扩张
                //     ++cur[s[right]];
                //     if(m.count(s[right]) && cur[s[right]] >= m[s[right]])
                //         ++match;
                // }
            //}
            else{//窗口太小向右扩张
                ++right;
                ++cur[s[right]];
                if(m.count(s[right]) && cur[s[right]] == m[s[right]])
                    ++match;
            }
            
        }       
        res = s.substr(res_s, res_e - res_s + 1);
        return res;
    }
};

另一种代码写法

class Solution {
public:
    string minWindow(string s, string t) {
        //滑动窗口
        int left = 0, right = 0, match = 0;
        int st = 0, minlen = INT_MAX;
        map<char, int> m, cur;
        string res;
        //1.统计t中的字符数
        for(char c : t)
            ++m[c];
        //2.寻找最小覆盖子串
        while(right < s.size()){  
            char c = s[right];
            if(m.count(c)){//只统计滑动窗口中在s中的字符
                ++cur[c];
                if(cur[c] == m[c])
                    ++match;
            }
            //++right;
            while(match == m.size()){
                char c1 = s[left];
                if(right - left + 1 < minlen){
                    st = left;
                    minlen = right - left + 1;
                }                
                if(m.count(c1)){
                    if(cur[c1] == m[c1])
                        --match;
                    --cur[c1];                    
                }                 
                ++left;
            }
            ++right;
            
        }
        res = (minlen == INT_MAX)? "" : s.substr(st, minlen);
        return res;
    }
};
发布了217 篇原创文章 · 获赞 9 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_31672701/article/details/104054389
今日推荐