76. 最小覆盖子串

· 约 2 分钟阅读 · 次阅读 leetcode

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。

 

注意:

对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 如果 s 中存在这样的子串,我们保证它是唯一的答案。  

示例 1:

输入:s = “ADOBECODEBANC”, t = “ABC” 输出:“BANC” 示例 2:

输入:s = “a”, t = “a” 输出:“a” 示例 3:

输入: s = “a”, t = “aa” 输出: "" 解释: t 中两个字符 ‘a’ 均应包含在 s 的子串中, 因此没有符合条件的子字符串,返回空字符串。


双指针方案

核心问题是判断窗口内的子串是否覆盖了目标串。

class Solution {
    unordered_map<char, int> mapT, mapS;
public:
    string minWindow(string s, string t) {
        int sLen = s.size();
        int tLen = t.size();
        if (sLen == 0 || tLen == 0 || sLen < tLen) {
            return "";
        }

        for (auto c : t) {
            ++mapT[c];
        }
        int begin=0,count=sLen+1;
        int left = 0, right = 0;
        // distance记录滑动窗口内部包含的t中的元素的个数, 若窗口中某个字符个数超过t中该元素的个数,distance不增加
        int distance = 0;
        // [left, right)
        while (right < sLen) {
            // 右指针右移,如果字符不在t中,则指针继续右移,直到碰到t中的字符。
            if (mapT[s[right]] == 0) {
                right++;
                continue;
            }
            // 如果这个字符在滑动窗口内的个数小于需要的个数,则表明此时右移对结果有帮助,distance加1
            if (mapS[s[right]] < mapT[s[right]]) {
                distance++;
            }
            // 更新窗口中字符的个数,然后右指针继续右移
            ++mapS[s[right]];
            right++;

            // 当distance和t的长度一致,说明碰到了一个可能的解
            while (distance == tLen) {
                // 判断是否是最优解并更新
                if (right-left < count) {
                    begin = left;
                    count = right-left;
                }

                //如果左指针对应字符不是需要的元素,则指针右移
                if (mapT[s[left]] == 0) {
                    left++;
                    continue;
                }
                // 左指针右移的时候,窗口中字符个数在减少,当字符为需要字符且个数不多时,左指针继续右移会让距离减1
                if (mapS[s[left]] == mapT[s[left]]) {
                    distance--;
                }
                --mapS[s[left]];
                left++;
            }

        }

        // cout << begin << " " << count;
        // 若count未更新
        if (count == sLen+1) {
            return "";
        }
        return s.substr(begin, count);
    }
};