【每日一题】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);
    }
};

如果有问题,欢迎大家指正!!!

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