[76] leetcode smallest coverage substring (string, double pointer)

Topic links: https://leetcode-cn.com/problems/minimum-window-substring/

Title Description

Give you a string S, a string T, please find inside the string S: T contains all the letters of the smallest sub-string.

Example:

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

Description:

如果 S 中不存这样的子串,则返回空字符串 ""。
如果 S 中存在这样的子串,我们保证它是唯一的答案。

Thinking

Violence Act

If violent method, time complexity than O (n ^ 3), the timeout. .

/*
 * 暴力解法
 * 超时
 */
class SolutionI {
public:
    string minWindow(string s, string t) {
        int minLen = INT_MAX;
        string ret;
        sort(t.begin(), t.end());
        if(s==t) return s;
        if(s.size() < t.size()) return ret;
        for (int i = 0; i <= s.size() - t.size(); ++i) {
            for (int j = i+t.size()-1; j < s.size(); ++j) {
                string sub = s.substr(i,j-i+1);
                int cnt = 0;
                sort(sub.begin(),sub.end());
                for (int k = 0; k < sub.size() && cnt < t.size(); ++k) {
                    if(sub[k] == t[cnt])
                        cnt ++;
                }
                if(cnt == t.size()){
                    if(sub.size() < minLen){
                        minLen = sub.size();
                        ret = s.substr(i,j-i+1);
                    }
                }
            }
        }
        return ret;
    }
};

Sliding window 2 - the double pointer O (n)

Sliding window algorithm thinking is this:

1, we use the string S in about two-pointer in pointer skills, initialize left = right = 0, the index closed interval [left, right] is called a "window."

2, let's continue to increase right pointer extended window [left, right], the string until the window meets the requirements (includes all the characters in T).

3. At this point, we stop increasing right, turn left pointer growing narrow window [left, right], the string until the window is no longer meet the requirements (does not contain all the characters in the T). At the same time, each time increasing the left, we have to update a result.

4. Repeat steps 2 and 3 until reaching the right end of the string S.

In fact, this idea is not difficult, step 2 is equivalent to looking for a "viable solution", and then step 3 in the optimization of this "feasible solution", finally found the optimal solution. Left and right hand turns forward, increasing and reducing the window size, the window continues to slide to the right.

Understand how the following drawing, corresponding to the counter window and Needs, T are recorded in a corresponding number of characters appear and the number of characters in the window.

Initial state:
Here Insert Picture Description
increased right, until the window [left, right] T includes all the characters:
Here Insert Picture Description
now started to increase left, narrow window [left, right].
Here Insert Picture Description
Until String window no longer meet the requirements, it left no longer continue to move.
Here Insert Picture Description
After repeating the above process, the first moving right, left ...... then move right until the pointer reaches the end of the string S, the algorithm ends.

The time complexity of the algorithm is O (M + N), M and N are the length of the string S and T. Since we first loop through the string for use to initialize Needs T, time O (N), up to two cycles after execution while 2M times at O ​​(M).

Note : Although there are two nested while, but the total time is not M ^ 2; because the number of times while the implementation is two-pointer left and right take the total distance, at most 2M.

Complexity Analysis

  • Time complexity: O (m + n)
  • Space complexity: O (n)
/*
 * 滑动窗口-双指针法
 * left指针收缩窗口;right指针扩大窗口
 * 先找到一个可行窗口,再不断收缩
 * 时间复杂度O(|S|+|T|) 空间复杂度O(|S|+|T|)
 */
class Solution {
public:
    string minWindow(string s, string t) {
        if(s.empty() || t.empty())
            return "";
        string ret;
        unordered_map<int, int> require; // 建立字典对t的字符进行计数
        unordered_map<int, int> window;
        for(char c:t)
            require[c] ++;

        int left = 0, right = 0;    // 双指针
        int match = 0;              // 记录window中已经有多少字符符合要求了
        int minLen = INT_MAX;
        int begin = 0;              // 最小子串的起始点

        while (right < s.size()){
            // 右指针右移加入字符扩大窗口
            char c1 = s[right];
            if(require.count(c1)){
                window[c1] ++;
                if(window[c1] == require[c1])
                    match ++;
            }
            right ++;

            // 左指针右移缩小窗口
            while (match == require.size()){
                if (right - left < minLen){
                    begin = left;
                    minLen = right - left;
                }
                char c2 = s[left];
                if(require.count(c2)){
                    window[c2] --;
                    if(window[c2] < require[c2])
                        match--;
                }
                left++;
            }
        }

        return minLen == INT_MAX? "" : s.substr(begin, minLen);
    }
};

Here Insert Picture Description

Guess you like

Origin blog.csdn.net/zjwreal/article/details/94574685