76. Minimum Window Substring

Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If there is no such substring, return the empty string "".

The testcases will be generated such that the answer is unique.

substring is a contiguous sequence of characters within the string.

Example 1:

Input: s = "ADOBECODEBANC", t = "ABC"
Output: "BANC"
Explanation: The minimum window substring "BANC" includes 'A', 'B', and 'C' from string t.

Example 2:

Input: s = "a", t = "a"
Output: "a"
Explanation: The entire string s is the minimum window.

Example 3:

Input: s = "a", t = "aa"
Output: ""
Explanation: Both 'a's from t must be included in the window.
Since the largest window of s only has one 'a', return empty string.

Constraints:

  • m == s.length
  • n == t.length
  • 1 <= m, n <= 105
  • s and t consist of uppercase and lowercase English letters.

Follow up: Could you find an algorithm that runs in O(m + n) time?

题目要求在已知字符串s中找出能包含t中所有字符的最小子字符串。简单方法就是以s每个字符为起点,每次遍历字符t的长度。但这种时间复杂度为O(mn),题目要求时间复杂度为O(m+n). ‘

因此采用滑窗法,两根指针,一根代表子字符串开始,一根代表子字符串的结尾(结尾每次走一个字符,因此可以用循环来代替),用一个hashmap记录字符串t中每个字符出现的次数,遍历字符串t循环n次,此时遇到字符c后mp[c]++。遍历字符串s时,遇到t中存在的字符,将hashmap中的次数减少1。

class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map<char, int> mp;
        
        //遍历字符串t,记录字符出现次数
        for(auto c : t) mp[c]++;
        
        //start记录当前子字符串开始位置
        //len记录当前最短符合要求的子字符串,初始值为最大值
        //pos记录当前最短符合要求的子字符串开始位置,初始值为-1,即无符合要求子字符串
        //count记录当前子字符串中包含t字符串所有字符的个数,每次mp[c]为0时更新一次
        int start = 0, len = INT_MAX, pos = -1, count = 0;
        for(int i=0; i<s.length(); i++){
            if(!mp.count(s[i])) continue;
            mp[s[i]]--;
            if(mp[s[i]] == 0){
                count++;
                if(count < mp.size()) continue; //t中还有字符未全包含在当前子字符串中continue
                
                //当前子字符串包含t中所有字符,收缩开始位置使得字符串最短
                while(start <= i){
                    while(start<=i && !mp.count(s[start])) start++;
                    if(mp[s[start]] < 0){
                        mp[s[start]]++;
                        start++;
                    } else break;
                }
                
                //计算当前子字符串长度,更新结果
                if(i-start+1 < len){
                    len = i-start+1;
                    pos = start;
                }
                
                //找下一个子字符串的开始位置
                mp[s[start]]++;
                start++;
                count--;
                while(start <= i){
                    while(start<=i && !mp.count(s[start])) start++;
                    if(mp[s[start]] < 0){
                        mp[s[start]]++;
                        start++;
                    } else break;
                }
            }
        }
        if(pos == -1) return "";
        return s.substr(pos, len);
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值