1. 程式人生 > >最小視窗子字串 LEETCODE 探索提升遇到的第一個困難的題目。

最小視窗子字串 LEETCODE 探索提升遇到的第一個困難的題目。

最小視窗子字串

給定一個字串 S 和一個字串 T,請在 S 中找出包含 T 所有字母的最小子串。

示例:

輸入: S = "ADOBECODEBANC", T = "ABC"
輸出: "BANC"

說明:

  • 如果 S 中不存這樣的子串,則返回空字串 ""
  • 如果 S 中存在這樣的子串,我們保證它是唯一的答案

原題地址

問題已經很具體了,分析ac程式碼。

class Solution {
public:
  string minWindow(string s, string t) {
        vector<int> map(128,0);
        for(auto c: t) map[c]++;
        int counter = t.size(), begin = 0, end = 0, d = INT_MAX, head = 0;
        while(end<s.size()){
            if(map[s[end++]]-- > 0) counter--; //in t
            while(counter == 0){ //valid
                if(end - begin < d)  d = end - (head = begin);
                if(map[s[begin++]]++ == 0) counter++;  //make it invalid
            }  
        }
        return d==INT_MAX? "":s.substr(head, d);
    }
};

定義ascII 128 字元hash 是在字串處理中,檢測是否出現過的常用做法。 

通過第一行第二行程式碼確定了需要包含的字元範圍;我最初的想法是建立一個unorder_map 實質是一樣的。 

對於字串處理這種方法更經濟直觀。 

對於擷取子串來說。 在 counter 等於零的時候 , 

end  到 begin 一定是一條包含子串,這個時候 需要判斷是否是最短的子串。 

長度就等 end - begin。先記錄下來。 然後在改變原先的map 現在需要的是繼續搜尋下一串子串,頭指標前移hash自加。但是問題是這樣不就不知道子串是不是包含t 了麼。依然是知道的。注意看if(map[s[end++]]-- > 0) counter--; //in t 這個程式碼。在這裡map中原來為1的變成了零,但是原來沒有的字元變成的是-1;在雜湊中就實現了不包含的字串就跳過了。當等於零的點在後一個迴圈中又出現時,說明包含的字元出現了,那麼給他自加到1,而沒有包含的字元從-1自加到零。counter 在自加1。跳出內層迴圈。同時相當於扔掉最早的出現的一個包含字元。尾部繼續搜尋最先出現的這個字元。

整個演算法拆開來就是這樣。 其中關鍵的有幾點 

主迴圈只走一遍,end 在迴圈內無腦自加,同時利用hash檢測是否包含。同時又標記是否遍歷過。 記錄當前查詢進度

內層迴圈 主要功能 第一記錄當前找到的字串長度,與位置。第二,丟掉最先找到的包含字元,讓外迴圈繼續尋找這個字元在尾部。