【Hot 100 刷题计划】 LeetCode 76. 最小覆盖子串 | C++ 滑动窗口题解

LeetCode 76. 最小覆盖子串 | C++ 滑动窗口高阶模板题解

📌 题目描述

题目级别:困难 (Hard)

给定两个字符串 st,长度分别是 mn。返回 s 中的 最短窗口 子串,使得该子串包含 t 中的每一个字符(包括重复字符)。如果没有这样的子串,返回空字符串 ""

测试用例保证答案唯一。

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

💡 解题思路:滑动窗口通用模板

寻找满足某种条件的"最短子串",是滑动窗口 的绝对主场。这道题的核心难点在于:如何快速判断当前窗口内是否已经凑齐了 t 中的所有字符?

我们引入两个哈希表 needwindows,以及一个极其巧妙的变量 valid

  • need:记录字符串 t 中每个字符需要的数量。
  • windows:记录当前滑动窗口中,这些目标字符出现的数量。
  • valid:记录当前窗口中,已经满足数量要求的字符种类数 。当 valid == need.size() 时,说明窗口已经完全覆盖了 t

核心运作机制:两步走战略

  1. 步骤一:向右扩张(寻找可行解)

    右指针 r 不断向右移动,把新字符加入 windows。如果加入的字符恰好是 need 中需要的,并且数量刚好达标,我们就让 valid++
    目标:一直向右扩张,直到 valid == need.size(),此时我们找到了一个"可行解"(虽然可能很长)。

  2. 步骤二:向左收缩(优化最优解)

    一旦窗口满足了条件(valid == need.size()),我们就暂存当前的子串长度和起始位置,并尝试逼近极限

    左指针 l 开始向右移动,把字符从窗口中"吐出来"。如果吐出的字符恰好是关键字符,且导致窗口内该字符的数量低于了 need 的要求,那 valid--,窗口不再合法。
    目标:剥离边缘的无用字符,找到满足条件的"最短"长度。

窗口就在这样"扩张 -> 满足条件 -> 收缩 -> 不满足条件 -> 再次扩张"的博弈中,不断刷新最短记录,直到遍历完整个字符串。


💻 C++ 代码实现

cpp 复制代码
class Solution {
public:
    string minWindow(string s, string t) {
        // need 记录目标字符串 t 中每个字符的需求量
        // windows 记录当前窗口中对应字符的拥有量
        unordered_map<char, int> windows, need;
        for (char c : t) need[c]++;

        int l = 0, r = 0;
        int valid = 0; // 记录窗口中满足 need 条件的字符种类数
        
        // 记录最小覆盖子串的起始索引及长度
        int st = 0, len = INT_MAX;

        while (r < s.size()) {
            // c 是将移入窗口的字符,同时右指针向右移动
            char c = s[r++];

            // 进行窗口内数据的一系列更新
            if (need.count(c)) {
                windows[c]++;
                // 当该字符的数量刚好达到目标要求时,满足条件的种类数 +1
                if (windows[c] == need[c]) {
                    valid++;
                }
            }

            // 判断左侧窗口是否要收缩 (当所有的字符种类都达标时)
            while (valid == need.size()) {
                // 在这里更新最小覆盖子串的记录
                if (r - l < len) {
                    st = l;
                    len = r - l;
                }

                // d 是将移出窗口的字符,同时左指针向右移动
                char d = s[l++];

                // 进行窗口内数据的一系列更新
                if (need.count(d)) {
                    // 如果移出的字符是关键字符,且移出后数量不达标了,种类数 -1
                    if (windows[d] == need[d]) {
                        valid--;
                    }
                    windows[d]--;
                }
            }
        }

        // 返回最小覆盖子串,如果没有找到则返回空字符串
        return len == INT_MAX ? "" : s.substr(st, len);
    }
};
相关推荐
我头发多我先学1 天前
C++ 模板全解:从泛型编程初阶到特化、分离编译进阶
java·开发语言·c++
yu85939581 天前
MATLAB连续线性化模型预测控制(SL-MPC)
算法·机器学习·matlab
星星码️1 天前
C++选择题练习(一)
开发语言·c++
ytttr8731 天前
基于ACADO工具包的自主车道跟踪与避障MPC控制
算法
隔壁大炮1 天前
第一章_机器学习概述_03.机器学习_算法分类
算法·机器学习·分类
WolfGang0073211 天前
代码随想录算法训练营 Day43 | 图论 part01
算法·深度优先
叶小鸡1 天前
小鸡玩算法-力扣HOT100-堆
数据结构·算法·leetcode
小雅痞1 天前
[Java][Leetcode simple] 28. 找出字符串中第一个匹配项的下标
java·开发语言·leetcode
何陋轩1 天前
【重磅】悟空来了:国产AI编程助手深度测评,能否吊打Copilot?
人工智能·算法·面试