每日LeetCode —— 76. 最小覆盖子串

231 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情

题目描述

       给定两个字符串s、t,要求找出str1中包含str2所有字符的最小长度的子串,若没有符合的子串则返回空字符串""。

例1:输入:s="ABBBDCFABEC" t="AC"  输出:"CFA"

解释:可以看出s中包含t所有字符的子串有"ABBBDC"、"ABEC"、"CFA"等,但最短子串为"CFA"。

例2:输入:s="ABBBDCFABEC" t="CAC"  输出:"CFABEC"

解释:s中包含t所有字符的子串有"ABBBDCFABEC"、"CFABEC"等,但是最短的一个子串为"CFABEC"。

本题值得注意的地方

  • s、t均由英文字符组成。
  • s中包含t所有字符要求字符种类和数目都要包含,例如例2中所返回的子串要包含两个C一个A。

原题地址:76. 最小覆盖子串

解题思路

       找符合要求的连续子串的问题可以使用双指针解决,在找到一个符合要求的子串后比较之前的子串,保留最短的那个一个子串。本题中为方便在子串时判断是否包含了所有的字符数,这里采用map用来计数,记录str2中每个字符出现的次数。

       使用per、end两个指针用来记录子串的开始、结束的位置,在处理end时,找到当前end后面第一个在t中出现的字符,然后处理per,如果s[per]位置的字符没有出现在t中或者该位置的字符在子串中的个数大于在t中的个数,则可以让per后移。在处理完当前一轮per、end后,可以根据子串的情况来判断是否更新并存储最短子串的信息。为了方便判断s中是否有符合的子串,这里用num记录子串中所包含t中字符的个数,如果最后num<s.lenth则说明没有符合的子串,返回 "" 即可。

实现代码

class Solution {
public:
    string minWindow(string s, string t) {
        // 记录str2中字符出现的次数情况
        map<char,int> map;
        for(int i = 0;i<t.size();i++) map[t[i]]++;
        // 记录结果子串的开始位置、当前子串开始位置、结束位置、子串长度
        int resper=0, per=0, end=0, len=INT_MAX, num=t.size();
        // 寻找子串
        for(;end < s.size(); end++){
            while(end < s.size() && map.count(s[end]) == 0) end++;
            if(map[s[end]] > 0)  num--;
            map[s[end]]--;
            while(per < end && (map.count(s[per]) == 0 || map[s[per]] < 0)){
                if(map.count(s[per]) > 0) map[s[per]]++;
                per++;
            }
            // 更新最短子串的开始位置和长度
            if(num==0 && end<s.size() && end-per+1 < len) len = end-per+1,resper = per;
        }
        if(num == 0) return s.substr(resper,len);
        else return "";
    }
};