76. 最小覆盖子串

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

本题的思想是哈希+滑动窗口,使用哈希构建sStr(s子串中字符出现次数)和tStr(t字符串中字符出现次数),如果sStr能够覆盖tStr,则当前子串符合条件,记录当前子串左端位置和长度,以便最后分割子串,并将子串左端位置右移一位;如果不能覆盖,则将子串右端位置右移一位。
代码如下:

class Solution {
public:
    //定义两个哈希表,tstr用来存放t中元素的出现次数信息,sstr用来存放滑动窗口中元素的出现次数信息
    unordered_map<char,int> tstr,sstr;

    //检查当前的窗口是否是合格的窗口,即:
    //检查当前滑动窗口中元素是否完全覆盖了字符串t中的所有元素(重点是某元素的出现次数必须不小于t中对应元素的出现次数)
    bool check()
    {
        for(auto tchar : tstr)
            {
                if(tchar.second > sstr[tchar.first]) return false;//注意这里的判断条件是大于
                //只要sstr中元素的second值不小于tchar中对应元素的second值就行
            }
        return true;
    }

    string minWindow(string s, string t) {
        int n1 = s.size(),n2 = t.size();
        if(n1<n2) return "";//如果t串比s串还长,s中肯定不能找到相应的子串
        int len = INT_MAX;//最小窗口的长度
        int ans_left = -1;//最小窗口的左边界指针
        //构造哈希表
        for(auto tchar : t)
            ++tstr[tchar];
        
        int left = 0,right = 0;//窗口的左右两端指针
        //滑动窗口右端指针遍历整个s串
        for(int right = 0;right<n1;right++)
        {   
            //每遍历一个元素,更新sstr中的元素信息
            ++sstr[s[right]];
            //如果当前遍历到的元素在tstr中也有,说明此次遍历的更新是有效的更新,否则不用管,直接继续遍历
            if(tstr.find(s[right]) != tstr.end())
            { 
                //对于每一次有效的更新,检查当前窗口中的子串是否是一个合格的子串
                while(check() && left<=right)
                {
                    //如果当前子串是合格的,那么判断是否是最小的窗口
                    if(len > right - left +1)
                    {
                        //如果是最小的窗口,那么更新窗口信息
                        ans_left = left;
                        len = right - left + 1;
                    }

                    //当前子串如果是合格的,那么尝试移进窗口的左边界缩短窗口的长度
                    --sstr[s[left]];//窗口左边界的元素信息从哈希表sstr中删除
                    left++;//移进窗口左边界

                    //移进之后,继续while判断移进后的子串是否是合格的,如果是合格的,继续重复同样的操作,更新窗口的信息
                }

                //一旦窗口不合格,窗口右边界的指针就继续往后遍历,拓宽窗口的长度
            }
        }
        if(ans_left == -1) return "";
        else return s.substr(ans_left,len);
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值