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);
    }
};
學如逆水行舟,不進則退
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章