1

1. 题目

Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

For example,
S = "ADOBECODEBANC"
T = "ABC"
Minimum window is "BANC".

Note:
If there is no such window in S that covers all characters in T, return the empty string "".

If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.

2. 思路

头尾指针遍历的思路。先遍历尾指针,找到全部t覆盖,然后移动头指针找到最小的子串,比较是否是当前最小。
然后继续移动一次头指针后,去掉一个有效字符,重新开始一轮的循环。

为了方便记录是否已经找到全部的,对t用一个字符频次数组来计数,找到一个队频次减一。为了方便观察数组是否全部覆盖,另外维护一个有效减位的计数,当计数达到t的长度时就是一次完全覆盖。然后再查找最小覆盖时,如果是无效字符,或者是有效但多出来频次的字符都继续跳过。

3. 代码

耗时:9ms

class Solution {
public:
    // 字符的值域空间是128,用128位的数组表示t中每个字符出现的次数
    // 头、尾两个指针。尾指针一直向前扫描,直到覆盖全部的t,假设指向i。
    // 然后头指针向后移动,直到找到以i结尾的最小长度。
    // 记录下当前的是否是最小子串。然后继续尾指针、头指针的这种扫描方式。
    string minWindow(string s, string t) {
        if (s.length() == 0 || t.length() == 0) { return ""; }
        int start = 0;
        int end = 0;
        int min_len = s.length() + 1;
        int cur_start = 0;
        int cur_end = 0;
        int t_freq[128];
        bool t_exist[128];
        bzero(t_freq, sizeof(t_freq));
        bzero(t_exist, sizeof(t_exist));
        for (int i = 0; i < t.length(); i++) {
            char ch = t[i];
            t_freq[ch]++;
            t_exist[ch] = true;
        }
        
        int ls = s.length();
        int lt = t.length();
        int cnt = 0;  // 记录需要的字符出现过多少次,方便判断是否已经包含全部的t
        while (cur_end < ls) {
            char ch = s[cur_end];
            if (!t_exist[ch]) { cur_end++; continue; }
            if (t_freq[ch] > 0) {
                cnt++;
            }
            t_freq[ch]--;
            cur_end++;
            if (cnt == lt) {
                while (cur_start < cur_end) {
                    char ch = s[cur_start];
                    if (!t_exist[ch]) { cur_start++; continue; }
                    if (t_freq[ch] < 0) { t_freq[ch]++; cur_start++; continue; }
                    else {
                        // find one candidate substr
                        int cur_len = cur_end - cur_start;
                        if (cur_len < min_len) {
                            min_len = cur_len;
                            start = cur_start;
                            end = cur_end;
                        }
                        cnt--;
                        t_freq[ch]++;
                        cur_start++;
                        break;
                    }
                }
            }
        }
        if (min_len <= ls) { return s.substr(start, min_len); }
        else { return ""; }
    }
};

knzeus
72 声望28 粉丝

行万里路,读万卷书