LeetCode 76:最小覆盖字串(滑动窗口详解)

题目

给你一个字符串 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 由英文字母组成


思路

由题可知,实际是在寻找 包含t的 最短子字符串 那么就需要考虑: Q1:如何达成包含? A1:选择哈希表解决字母和个数问题 Q2:怎样寻找最短? A2:使用滑动窗口框住符合要求的子字符串 再缩小窗口寻找合适左边界,得到符合题意窗口大小 依次移动,直至滑动窗口结束指针到达字符串s末尾

解题过程

1.准备工作

创建两个哈希表 1.needT用于统计字符串t中的字母及其个数 (统计完就可以不管 字符串t 了,使命完成!我们去运用获得到的 统计数据needT 就OK) 2.haveS用于记录滑动窗口框住的字母及其个数
设置两个指针 1.起始指针i 2.终止指针j 滑动窗口需要先移动终止指针到第一个符合题意的位置 再移动起始指针,缩小窗口、 再增设一个int型变量cnt 用于统计符合要求的字母个数,可以理解为收集进度 还需要一个 string型变量ans 存储最后的最小覆盖字串 返回

2.逻辑代码

for循环开始 终止指针j向后移动 记录走过的每一个s[j],存至haveS中 如果 s[j] 的出现次数(即存入haveS中的s[j]对应个数)小于等于 needT[s[j]](满足题目需要的该字母个数) 收集进度cnt +1 当收集到的字母个数大于需要的 开始缩小滑动窗口 终止指针j 不变,向后移动 起始指针i 同时在 haveS 中去掉 i指针 所对应的 字母s[i]
当收集进度达到目标即 字符串t的长度(t限时返厂了哈) 动手比较得到最短窗口 这里还需要考虑没有匹配到合适子字符串的情况(即窗口为空) 取最小值更新 用字符串的substr方法切割最短的字串 最后返回该字串

3.复杂度

  • 时间复杂度: O(n)

4.Code

class Solution {

public:

    string minWindow(string s, string t) {

        unordered_map<char,int>needT,haveS;

        string ans;

        int cnt=0;

        

        // 统计 t 中每个字符的出现次数

        for (char c : t) {// 遍历字符串 t

            needT[c]++;// 增加对应字符的值

        }

        //滑动窗口!!!

        for(int j = 0,i = 0; j < s.size();j++){

            haveS[s[j]]++;//终止指针后移,读取s存入

            

            // 如果 s[j] 的出现次数小于等于 needT[s[j]],收集进度 +1

            if(haveS[s[j]] <= needT[s[j]]){//还没收集齐

                cnt++;//收集进度+1

            }

            

            //缩小窗口左边界

            while(haveS[s[i]] > needT[s[i]]){

            //在初始位置的这个字母的个数 拥有大于需要

                haveS[s[i]]--;//去掉

                i++;//起始指针向后移动

            }

            //收集完毕

            if (cnt == t.size()) {

                if (ans.empty() || j - i + 1 < ans.size()){

                //如果窗口为空,或当前窗口长度小于现存,更新

                    ans = s.substr(i, j - i + 1);

                }

            }

        }

        return ans;//返回最小字符串

    }

};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值