【每日一題】LeetCode. 76. 最小覆蓋子串

每日一題,防止癡呆 = =

一、題目大意

給你一個字符串 S、一個字符串 T,請在字符串 S 裏面找出:包含 T 所有字符的最小子串。
在這裏插入圖片描述
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/minimum-window-substring

二、題目思路以及AC代碼

對於這種找子串的題,思路其實也不是很複雜,目前看來無非是雙指針的方法或者DP,稍加思考也可以得到答案。

思路

本題的思路就是利用雙指針,即 l 和 r,開始都在字符串最左端,當 l 和 r 所構成的子串不包含 t 中的元素時,那麼我們可以通過移動 r,來使子串加長,直到包含 t 中的元素,驗證其是否是最短的包含 t 的子串;然後由於我們在滑動的時候,可能會經過許多重複的元素,比如t = [A, B, C],s = [A, D, A, B, B, D, C],那麼我們在保持 l=0 時,去移動右邊界 r 到C的過程中,會經過好幾個A和B,那麼此時他們都是候選的子串,所以我們要再次移動左邊界,來檢查這些情況,直到移動左邊界導致子串不包含 t 了,再重新移動右邊界,如此反覆即可。

AC代碼
#define INF 2147483647

unordered_map<char, int> t_map;
unordered_map<char, int> w_map;

bool check() {
    for (unordered_map<char, int>::iterator it=t_map.begin();it!=t_map.end();it++) {
        if (w_map[it->first] >= it->second) continue;
        else return false;
    }
    return true;
}

class Solution {
public:
    string minWindow(string s, string t) {
        t_map.clear();
        w_map.clear();

        int t_len = t.length();
        for (int i=0;i<t_len;i++) {
            t_map[t[i]]++;
        }

        int l = 0, r = 0;
        int s_len = s.length();
        int rl = -1, rr = -1;
        int rlen = INF;
        w_map[s[0]] = 1;
        while (l <= r && r < s_len) {
            if (check()) {
                if (r - l + 1 < rlen) {
                    rlen = r - l + 1;
                    rl = l;
                    rr = r;
                }
                w_map[s[l]]--;
                l++;
            }
            else {
                r++;
                if (r >= s_len) break;
                w_map[s[r]]++;
            }
        }

        if (rr == -1) return "";
        return s.substr(rl, rr - rl + 1);
    }
};

如果有問題,歡迎大家指正!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章