最小覆盖子串 - 剑指offer困难

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

对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。

示例 2:

输入:s = "a", t = "a"
输出:"a"
解释:整个字符串 s 是最小覆盖子串。

示例 3:

输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。

提示:

m == s.length
n == t.length
1 <= m, n <= 105
s 和 t 由英文字母组成
进阶:你能设计一个在 o(m+n) 时间内解决此问题的算法吗?
解题思路
  • 滑动窗口,双指针
  • 可以使用unordered_map<char,int>mt统计字符串s的字符个数
  • 然后设定两个指针lr,以及unordered_map<char,int>ms维护l到r之间的字符数量
  • 如果ms符合要求,那么l指针向右移动,缩小窗口;如果ms不符合要求,那么r指针向右移动,扩张窗口;
  • 此外有两个优化点需要注意:
    1. 指针移动过程中可以剔除不在t中的字符;
    2. 指针移动过程中可以剔除ms中数量比mt多的冗余字符;
解题代码
class Solution {
public:
    unordered_map<char,int>ms, mt;
    string minWindow(string s, string t) {
        for(int i=0;i<t.length();i++){
            mt[t[i]]++;
        }
        string ans="";
        int max_len=1e5+5;
        int l=0,r=0;
        ms[s[r]]++;
        while(l<=r&&r<s.length()){
            bool ok=true;
            if(ms.size()>=mt.size()){
                unordered_map<char,int>::iterator iter = mt.begin();
                for(;iter!=mt.end();iter++){
                    if(ms[iter->first]<iter->second){
                        ok=false;
                        break;
                    }
                }
            }
            else ok=false;
            if(ok){
                if(max_len>r-l+1){
                    ans = s.substr(l,r-l+1);
                    max_len = r-l+1;
                }
                if(ms[s[l]]>0)ms[s[l]]--;
                else ms[s[l]]=0;
                l++;
                while(l<=r&&mt.count(s[l])==0)l++;
                while(l<=r&&ms[s[l]]>mt[s[l]])ms[s[l++]]--;

            }
            else{
                r++;
                if(r<s.length())ms[s[r]]++;
            }
            
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力搬砖的小王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值