76. 最小覆盖子串

给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。

示例:

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

说明:

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

思路:这个题目的思路是维护两个指针l 和 r(初值都为0),分别标识覆盖子串的开始位置和结束位置。采用哈希表bb记录每个字符数量,用一个for循环O(n)的时间复杂度来解决。接下来存在三个问题:1、什么时候更新左指针; 2、什么时候更新右指针; 3、什么时候更新最小覆盖子串

1、每次找到一个新的覆盖子串的时候,l就更新为下一个最近的t中存在的字符的位置。

2、每次找到一个新的覆盖子串的时候,r就更新为i。

3、当前覆盖子串比之前的短的时候。

那么什么时候算找到了一个新的覆盖字串儿呢?注意,t里面的字符可能是有重复的,所以说bb.size()== aa.size() 的时候不足以说明找到了一个新的覆盖子串,必须得是bb中的每一个字符的数目都大于等于aa中的每一个字符的数量,这一点我们通过哈希表来维护。

class Solution {
public:
    string minWindow(string s, string t) {
        string re;  
        map<char,int> aa, bb;
        for (auto x : t) ++aa[x];
        int l = 0, r = 0;
        for (int i = 0; i < s.size(); ++i){
            if (aa.count(s[i])){
                if (bb.empty())	l = i;//l的边界
                ++bb[s[i]];//维护哈希表
                while (bb.size()== aa.size()){//这里为什么用while?因为找到新的覆盖字串,更新l之后,这里面可能还有覆盖字串。
                    int flag = 1;
                    for (auto it = aa.begin(); it != aa.end(); ++it){
                        if ((*it).second > bb[(*it).first]) flag = 0;
                    }
                    if (flag) {//flag为1的时候说明找到了新的覆盖子串
                        r = i;//更新r
                        if (re.empty() || r - l + 1<re.size())//更新re
                            re = s.substr(l, r - l + 1);
                        if (--bb[s[l]] == 0) bb.erase(s[l]);//因为要移动l,维护下哈希表
                        while (l<s.size() - 1 && !aa.count(s[++l]));//更新l,注意l不要越界
                    }
                    else break;
                }
            }
        }
        return re;
    }
};

猜你喜欢

转载自blog.csdn.net/scarlett_guan/article/details/80385114