1. 程式人生 > 實用技巧 >76. 最小覆蓋子串

76. 最小覆蓋子串

76. 最小覆蓋子串

難度困難686給你一個字串 S、一個字串 T 。請你設計一種演算法,可以在 O(n) 的時間複雜度內,從字串 S 裡面找出:包含 T 所有字元的最小子串。 示例: 輸入:S = "ADOBECODEBANC", T = "ABC"
輸出:"BANC" 提示:
如果 S 中不存這樣的子串,則返回空字串 ""。
如果 S 中存在這樣的子串,我們保證它是唯一的答案。

思路:

我們可以用滑動視窗的思想解決這個問題,在滑動視窗型別的問題中都會有兩個指標。一個用於「延伸」現有視窗的 r 指標,和一個用於「收縮」視窗的 l 指標。在任意時刻,只有一個指標運動,而另一個保持靜止。我們在 s 上滑動視窗,通過移動 r 指標不斷擴張視窗。當視窗包含 t 全部所需的字元後,如果能收縮,我們就收縮視窗直到得到最小視窗。 如何判斷當前的視窗包含所有 ttt 所需的字元呢?我們可以用一個雜湊表表示 ttt 中所有的字元以及它們的個數,用一個雜湊表動態維護視窗中所有的字元以及它們的個數,如果這個動態表中包含 t 的雜湊表中的所有字元,並且對應的個數都不小於 t 的雜湊表中各個字元的個數,那麼當前的視窗是「可行」的。
注意:這裡 ttt 中可能出現重複的字元,所以我們要記錄字元的個數。 只讀元素:for(const auto& x:range) substr(start, length):返回一個從指定位置開始,並具有指定長度的子字串。 程式碼:
class Solution {
     unordered_map<char, int> hash_t, hash_s;

public:
    bool check()
    {
        for(const auto &p:hash_t)
        {
            if(p.second>hash_s[p.first])
                
return 0; } return 1; } string minWindow(string s, string t) { int left = 0, right = 0, res_l = -1, len = INT_MAX; for(const auto &c:t) { hash_t[c]++; hash_s[c] = 0; } while(right<s.size()) {
if(hash_t.find(s[right])!=hash_t.end()) hash_s[s[right]]++; while(check()&&left<=right) { if(right-left+1<len) { len = right-left+1; res_l = left; } hash_s[s[left++]]--; } right++; } return res_l == -1 ? string() : s.substr(res_l, len); } };