LeetCode | 76. Minimum Window Substring

题外话:

大雾霾的天气,适合待在屋子里刷题。

 

题目:

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).

Example:

Input: S = "ADOBECODEBANC", T = "ABC"
Output: "BANC"

Note:

  • If there is no such window in S that covers all characters in T, return the empty string "".
  • If there is such window, you are guaranteed that there will always be only one unique minimum window in S.

 

解题思路:

给出字符串S和T,题目要求在O(n)的时间复杂度前提下,找到S中包含T中所有字符的最小的子序列。

首先,我们需要统计T中所有的字符出现的字符种类和出现频率,可以用map来记录dict。除此之外,设置all_rec变量来统计T中包含的独一无二的字符种类数。

然后,对S字符串进行滑动窗口式的扫描,以满足“包含T中所有字符”及“最小子序列”。对S设置两个索引指针,l和r,分别对应左指针和右指针,以确定扫描窗口的范围。声明search为滑动窗口扫描的字符map,rec记录当前滑动窗口中,种类数和对应频率数与T相等的字符个数。

扫描过程可以理解为如下:

1. r指针向右扫描,每次移动一个位置,每移动一次,对search进行更新。如果当前字符S[r]不被包含在search中,则插入元组(S[r], 1),表示当前字符S[r]在滑动窗口中出现一次;若search已包含当前字符S[r],则对search[S[r]]++。

2. 更新完search之后,比较search[S[r]]和dict[S[r]]是否相等,如果相等,则更新rec++;若不相等,则无需操作。

3. 在判断完扫描窗口中的字符种类数后,若rec == all_rec,则扫描窗口search中包含所有dict中的字符,此时更新输出索引res_l和res_r。

4. 当右指针的范围已经可以保证rec == all_rec,开始更新左指针 l,以缩小search的范围。l同样向右移动,采用与r指针相似的更新策略。若l指针在缩小窗口范围的同时,保证search中包含字符种类及频率不变,则可更新res_l和res_r,找到更小的符合题意的子序列。

 

代码:

class Solution {
public:
    string minWindow(string s, string t) {
        if(s.length() < 1 || t.length() < 1)
            return "";
        map<char, int> dict;
        int all_rec = 0;
        for(int i = 0; i<t.length(); i++)
        {
            if(dict.find(t[i]) == dict.end())
            {
                dict.insert(pair<char, int>(t[i], 1));
                all_rec++;
            }
            else
                dict[t[i]]++;
        }
        
        map<char, int> search;
        int l = 0, r = 0, rec = 0, res_l = -1, res_r = s.length();
        
        while(l <= r && r < s.length())
        {
            if(search.find(s[r]) == search.end())
                search.insert(pair<char, int>(s[r], 1));
            else
                search[s[r]]++;
            
            if(dict.find(s[r]) != dict.end() && search[s[r]] == dict[s[r]])
                rec++;
            
            if(rec == all_rec && res_r - res_l + 1 > r - l + 1)
            {
                res_r = r;
                res_l = l;
            }
            
            while(rec == all_rec && l <= r)
            {
                search[s[l]]--;
                if(dict.find(s[l]) != dict.end() && search[s[l]] < dict[s[l]])
                    rec--;
                l++;
                if(rec == all_rec && res_r - res_l + 1 > r - l + 1)
                {
                    res_r = r;
                    res_l = l;
                }
            }

            r++;
        }
        
        if(res_l == -1)
            return "";
        return s.substr(res_l, res_r - res_l + 1);
    }
};

 

本题的整体思路也参考了leetcode官方给出的解答。不过代码的性能还可以优化。以下是leetcode官方给出的解答。

Algorithm

  1. We start with two pointers, leftleft and rightright initially pointing to the first element of the string SS.

  2. We use the rightright pointer to expand the window until we get a desirable window i.e. a window that contains all of the characters of TT.

  3. Once we have a window with all the characters, we can move the left pointer ahead one by one. If the window is still a desirable one we keep on updating the minimum window size.

  4. If the window is not desirable any more, we repeat step \; 2step2 onwards.

The above steps are repeated until we have looked at all the windows. The smallest window is returned.

 

Complexity Analysis

  • Time Complexity: O(|S| + |T|)O(∣S∣+∣T∣) where |S| and |T| represent the lengths of strings SS and TT. In the worst case we might end up visiting every element of string SS twice, once by left pointer and once by right pointer. |T|∣T∣ represents the length of string TT.

  • Space Complexity: O(|S| + |T|)O(∣S∣+∣T∣). |S|∣S∣ when the window size is equal to the entire string SS. |T|∣T∣ when TT has all unique characters. 

 

 

供自己以后方便回忆。欢迎大家多多讨论~

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值