leetcode.76:最小覆盖字串

本文介绍了一种利用滑动窗口和哈希表解决LeetCode上最小覆盖子串问题的方法,通过动态维护窗口内元素,实现了快速查找包含特定字符集合的最短子串。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。

示例:

输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”
说明:

如果 S 中不存这样的子串,则返回空字符串 “”。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
通过次数57,799提交次数152,286

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-window-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:hash+滑动窗口
首先题目是一定要用滑动窗口来做的,那么第一步就是思考如何查看滑动窗口内部的元素是否满足要求,对于本题目而言,可以先将目标字符串hash到int类型的数组之中,之后在遍历的过程之中,动态的维护窗口的int类型的hash数组,之后就可以通过比较两个数组来判断是否满足要求。其次,对于滑动窗口的移动来说,考虑对滑动窗口的结尾(即右侧)进行遍历,同时维护一个begin为滑动窗口的开端,每次遍历首先考虑当前的滑动窗口是否能够满足要求,如果不能则遍历下一个右端点,如果能够满足要求,那么尽量的将左端点向右移动以得到最短的滑动窗口,移动的条件是:1.当前左端点指向的元素不在目标字符串中;2.当前左端点指向的元素出现的次数大于目标字符串中该元素出现的次数。当不能继续移动的时候,比较此时的长度和记录的长度,存储下较小的长度和与该长度对应的begin和i值,以便返回结果。最后根据记录返回结果即可。
注:1. 对于字母的hash可以使用int类型的数组,而不必使用map。
2. 可以使用一个vector数组记录目标字符串出现的字符,以避免每次比对是否满足要求的时候都需要遍历整个数组;
3. 要考虑特殊情况,如没有满足要求的子串(将end设置为特殊的值);
4. 在leetcode中,进行输出耗时很长,所以在提交之前需要清除所有用于debug的输出语句。

class Solution {
public:
    string minWindow(string s, string t) {
        int tl = t.size();
        int sl = s.size();
        if(tl>sl)return "";

        int charmap_s[128];
        memset(charmap_s,0,sizeof(charmap_s));
        int charmap_t[128];
        memset(charmap_t,0,sizeof(charmap_t));

        vector<int> tv;
        
        for(int i = 0;i<tl;i++)
        {
            charmap_t[t[i]]++;
        }
        for(int i = 0;i<128;i++)
        {
            if(charmap_t[i]>0)
            tv.push_back(i);
        }

        int begin = 0;
        int start = 0;
        int end = -1;
        int min = sl;

        for(int i = 0;i<sl;i++)
        {
            charmap_s[s[i]]++;
            
            if(!isMatch(charmap_s,charmap_t,tv))
            {
                continue;
            }
            else
            {
                while(begin<i&&(charmap_t[s[begin]]==0||charmap_s[s[begin]]>charmap_t[s[begin]]))
                {
                    charmap_s[s[begin]]--;
                    begin++;
                }

                if((i-begin)<min)
                {
                    end = i;
                    start = begin;
                    min = end-begin;
                }
            }
        }

        string ret = "";
        if(end==-1)return ret;

        for(int i = start;i<=end;i++)
        {
            ret+=s[i];
        }
        
        return ret;
    }

    bool isMatch(int* s,int* t,vector<int>& tv)
    {
        for(int i = 0;i<tv.size();i++)
        {
            int index = tv[i];
            if(s[index]<t[index])return false;
        }
        return true;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值