LeetCode 76. 最小覆盖子串

描述

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。

注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例1:

输入:s = “ADOBECODEBANC”, t = “ABC”
输出:“BANC”

示例2:

输入:s = “a”, t = “a”
输出:“a”

提示:

  • 1 <= s.length, t.length <= 10^5
  • s 和 t 由英文字母组成

进阶:你能设计一个在 o(n) 时间内解决此问题的算法吗?

思路

使用滑动窗口,一前一后指针控制一个可变大小的窗口,在s字符串上滑动。使用两个哈希表window和needs,分别代表当前窗口内包含的字符串情况和t字符串情况。例如,t=“ABCA”,则
needs[A] = 2,needs[B] = 1,needs[C] = 1。

执行步骤如下:

  1. 首先,右指针先动,直到窗口中包含了t字符串中所有的字符为止;
  2. 此时,左指针再右移,每次都判断当前窗口是否仍包含t中所有字符,如果仍然包含,还要判断此时窗口是否更小,更新最小值,直到窗口内包含的字符不再包含t字符串中所有的字符为止;
  3. 直到右指针到达s字符串末尾后,左右指针包含的窗口不再符合要求,算法结束。

注:

在C++中,对哈希表键值访问时,如果键值不存在会自动创建此键值对并赋初值。这里我踩了个坑,在下面解答中的注释1和注释2处,我使用needs[key] != 0来判断needs哈希表中有没有当前字符,这会导致如果当前字符不存在会创建此字符的键值对,导致needs表的size发生变化,这样下面第2个while语句的判断条件match == needs.size()使用到needs.size()就会出问题,因为size会越来越大。如果要使用needs[key] != 0作为判断条件,需要一开始将needs.size()存储到一个变量needSize中,后面使用match ==needSize作为判断条件即可。

解答

class Solution {
public:
    string minWindow(string s, string t) {
        //初始化
        int minLen = INT_MAX;//limits.h中定义
        unordered_map<char, int> window;//window记录当前窗口中的字符及数量
        unordered_map<char, int> needs;//哈希表记录t中的字母及出现次数
        for(char tmp_c : t) needs[tmp_c] ++;//填充needs哈希表里的每个字符及次数
        int l = 0, r = 0;
        int match = 0;//记录window中符合要求的字符数
        int res_start = 0;//记录找到的更短字符串的起始位置

        //窗口开始移动
        while(r != s.size()){//right增加一个字符到结尾之前
            char c_right = s[r];
            //注释0: if(needs[c_right] != 0){
            if(needs.count(c_right)){ //说明当前字符是待查找的字符
                window[c_right] ++;//当前窗口中字符c +1
                if(window[c_right] == needs[c_right]) match ++;//一种字符匹配完成,计数+1         
            }
            r ++;//right右移一位
            
            //字符全部匹配,开始缩减左窗口
            while(match == needs.size()){
                if(r - l < minLen){//找到更短的匹配字符串
                    res_start = l;
                    minLen = r - l;
                }
                char c_left = s[l];
                if(needs.count(c_left)){
                //注释1: if(needs[c_left] != 0){
                    window[c_left] --;
                    //当window中字母出现的次数不再符合要求
                    if(window[c_left] < needs[c_left])
                        match --;
                }
                l ++;
            }

        }
        //substr()函数复制字符串
        return minLen == INT_MAX ? "" : s.substr(res_start, minLen);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值