76. 最小覆蓋子串

ouyangxx發表於2024-11-11
  1. 題目連結

  2. 解題思路

    • 求最小子串問題,第一時間,想「以i開頭的結果是什麼」,求出所有的結果,最優的便是;或者「以i結尾的結果是什麼」,求出所有的結果,最優的便是
    • 這個題使用「以i開頭的結果是什麼」,假設是[i, j]然後再求i+1的結果時,我們發現,只需要把i位置的字元去掉,就可以知道是否滿足結果,如果不滿足,我們可以直接把j往後接著找。有點像動態規劃的思想,我知道了dp[i],然後dp[i + 1]就可以利用dp[i]的結果,快速得到。
    • 其實這個題是一個「滑動視窗」的問題。i開頭,滑到j,也就是[i, j]就是i的結果,然後把i移除視窗,如果仍然滿足結果,那i+1的結果就是[i + 1, j],如果不滿足,j再右移,就是滑動視窗的做法。
    • 一些細節
      • 1️⃣怎麼知道「j滑到哪裡才滿足」?可以用一個map,key就是某個字元,value就是該字元需要的次數。假設一個map,有map['a'] = 2,a字元需要2次。當遇到a之後,減減,當a減到0的時候,我們就能知道,a這個字元滿足了,所以我們還需要用一個變數count記錄,有幾個字元已經滿足了。假設map的大小是5,就說明,一共有5種字元,當count == 5時,就說明全部滿足了。
      • 2️⃣得到i的結果[i, j]後,怎麼把i移除?如果i在map裡,現在i被移除了,所以map中對應的字元要++。
      • 那我怎麼知道把i移除之後,i+1是否滿足呢?還是count變數,當移除i,i對應的字元在map中,map就要++,如果++後,大於0了,說明,不滿足了。所以,這裡又有一個問題,1️⃣中,遇到map中的字元,就要減減,減到0後還要減嗎?要減!因為i移除之後,map要加加,如果此時還是小於等於0,那就說明i+1還是滿足條件的。
      • 總結一下:
        • 當遍歷到的字元,是需要的,map中對應的字元就要減減,如果減減後,等於0了,那麼count++,當count==5時,就說明滿足條件了
        • 當移除i時,如果在map中,那麼對應的字元就要加加,如果加加後,大於1了,那麼count--,此時j就要往右滑了。
  3. 程式碼

    class Solution {
    public:
        string minWindow(string s, string t) {
            int ans_len = INT32_MAX;    // 答案的長度
            int ans_index = -1;         // 答案的開始下標
            unordered_map<char, int> need;     // 需要滿足的字元
            int count = 0;
            // 構造需要滿足的字元
            for (auto &it : t) {
                need[it]++;
            }
            int n = s.size();
            int j = -1;    // 視窗右邊界
            for (int i = 0; i < n; ++i) {     // 以i開頭的答案是什麼?
                // 將i - 1移出視窗
                if (i - 1 >= 0 && need.count(s[i - 1]) != 0) {
                    if (need[s[i - 1]]++ == 0) {   // 等同於need[s[i - 1]]++; if (need[s[i - 1]] > 0)
                        count--;
                    }
                }
                while(j + 1 < n && count != need.size()) {    // 如果不滿足條件  j要往右擴
                    j++;
                    if (need.count(s[j]) != 0) {
                        if (need[s[j]]-- == 1) {   // 等同於need[s[j]]--; if (need[s[j]] == 0)
                            count++;
                        }
                    }
                }
                if (count == need.size()) {   // 滿足要求
                    if (j - i + 1 < ans_len) {   // 如果能更新
                        ans_len = j - i + 1;
                        ans_index = i;
                    }
                } else {     // j都越界了  還沒滿足要求  說明滿足不了了 後面的也滿足不了了
                    break;
                }
            }
            if (ans_index == -1) {   // 沒有找到
                return "";
            }
            return s.substr(ans_index, ans_len);
        }
    };
    

相關文章