LeetCode 76. 最小覆盖子串 【滑动窗口】

题目描述

给定两个字符串 S 和T,求 S 中包含T 所有字符的最短连续子字符串的长度,同时要求时间 复杂度不得超过O(n)。

解题思路

需要思考以下四个问题:

1、当移动 right 扩大窗口,即加入字符时,应该更新哪些数据?

2、什么条件下,窗口应该暂停扩大,开始移动left 缩小窗口?

3、当移动 left缩小窗口,即移出字符时,应该更新哪些数据?

4、我们要的结果应该在扩大窗口时还是缩小窗口时进行更新?

如果一个字符进入窗口,应该增加 window计数器;如果一个字符将移出窗口的时候,应该减少 window 计数器;当 cnt满足 need时应该收缩窗口;应该在收缩窗口的时候更新最终结果。

需要注意的是,当我们发现某个字符在window的数量满足了need的需要,就要更新 valid,表示有一个字符已经满足要求。而且,你能发现,两次对窗口内数据的更新操作是完全对称的。

cnt == need.size()时,说明T 中所有字符已经被覆盖,已经得到一个可行的覆盖子串,现在应该开始收缩窗口了,以便得到「最小覆盖子串」。

移动 left收缩窗口时,窗口内的字符都是可行解,所以应该在收缩窗口的阶段进行最小覆盖子串的更新,以便从可行解中找到长度最短的最终结果。

参考 :labuladong 大佬题解

AC

class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map<char,int> need,window;
        for(char c : t) need[c]++;
        int left=0,right=0,cnt=0;
        // 记录最小覆盖子串的起始索引及长度
        int start=0,len=INT_MAX;
        while(right<s.size()){
         	// c 是将移入窗口的字符
            char c = s[right];
            // 右移窗口
            right++;
            // 进行窗口内数据的一系列更新
            if(need.count(c)){
                window[c]++;
                if(window[c]==need[c])
                    ++cnt;
            }
            // 判断左侧窗口是否要收缩
            while(cnt==need.size()){
            	// 在这里更新最小覆盖子串
                if(right-left<len){
                    len=right-left;
                    start=left;
                }
                // dd 是将移出窗口的字符
                char dd = s[left];
                // 左移窗口
                left++;
                // 进行窗口内数据的一系列更新
                if(need.count(dd)){
                    if(window[dd]==need[dd]) --cnt;
                    window[dd]--;
                }
            }
        }
        return len == INT_MAX? "" : s.substr(start,len);
    }
};
学如逆水行舟,不进则退
原创文章 622 获赞 2443 访问量 41万+

猜你喜欢

转载自blog.csdn.net/weixin_42429718/article/details/105968276