当前位置: 首页 > news >正文

2.8滑动窗口专题:最小覆盖子串

1. 题目链接

LeetCode 76. 最小覆盖子串


2. 题目描述

给定字符串 st,要求找到 s最小的窗口,使得该窗口包含 t 的所有字符(包括出现次数)。若不存在,返回空字符串。
示例
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"(最短窗口包含 ABC,且长度最短)。


3. 示例分析

s = "ADOBECODEBANC", t = "ABC" 为例:

  1. 滑动窗口法:

    • right 移动到索引 5 时,窗口 "ADOBEC" 包含 ABC,记录长度为 6。
    • 继续移动 right 到索引 10,窗口缩小为 "BANC",长度为 4,更新为最终结果。
  2. 暴力枚举法:

    • 枚举所有子串,例如 [0,5][0,6][9,12],逐个检查是否包含 t 的所有字符。

4. 算法思路

滑动窗口法

  1. 哈希表统计
    • hash1 统计 t 中字符的出现次数。
    • hash2 统计当前窗口内字符的出现次数。
  2. 动态窗口调整
    • 右指针扩展:将字符加入窗口,若其出现次数等于 t 中的次数,增加有效计数 count
    • 左指针收缩:当窗口包含 t 的所有字符时,尝试缩小窗口并更新最小长度。
  3. 结果记录:每次窗口满足条件时,检查是否为最短窗口。

暴力枚举法

  • 枚举所有可能的子串起点 i 和终点 ji ≤ j),检查子串是否包含 t 的所有字符。

5. 边界条件与注意事项
  1. 字符重复性:窗口需满足 t 中字符的出现次数,而不仅是存在性。
    • 例如 t = "AA",窗口必须包含至少两个 A
  2. 无效输入:若 s 长度小于 t,直接返回空。
  3. 哈希表初始化:需覆盖所有 ASCII 字符(代码中使用 hash[128])。
  4. 最小窗口更新:需在每次窗口合法时实时更新,避免遗漏更优解。

6. 代码实现
class Solution {
public:
    string minWindow(string s, string t) 
    {
        int ns = s.size(), nt = t.size();
        if (ns < nt) return "";

        int hash1[128] = {0}; // 统计t的字符频次
        int kinds = 0;        // t中不同字符的种类数
        for (char ch : t) {
            if (hash1[ch]++ == 0) kinds++;
        }

        int hash2[128] = {0}; // 窗口内字符频次
        int left = 0, count = 0, min_len = INT_MAX, begin = -1;

        for (int right = 0; right < ns; right++) {
            char in_ch = s[right];
            hash2[in_ch]++; 
            // 当窗口内该字符频次首次满足t的要求时,增加count
            if (hash2[in_ch] == hash1[in_ch]) count++;

            // 当窗口包含t的所有字符时,尝试缩小窗口
            while (count == kinds) {
                // 更新最小窗口
                if (right - left + 1 < min_len) {
                    min_len = right - left + 1;
                    begin = left;
                }
                // 移除左边界字符
                char out_ch = s[left++];
                // 若移除后导致频次不足,减少count
                if (hash2[out_ch]-- == hash1[out_ch]) count--;
            }
        }

        return (begin == -1) ? "" : s.substr(begin, min_len);
    }
};

在这里插入图片描述


7. 暴力枚举法与滑动窗口法对比图表

对比维度暴力枚举法滑动窗口法
核心思想枚举所有子串,逐一检查是否包含 t 的所有字符。动态维护窗口,仅在窗口不满足条件时扩展,满足条件时收缩以寻找最优解。
时间复杂度O(n² * m)(n为s长度,m为t长度,需遍历所有子串并检查字符频次)。O(n)(每个字符被左右指针各访问一次)。
空间复杂度O(1)(使用固定大小的哈希表)。O(1)(哈希表大小为128,常数空间)。
实现方式双重循环枚举子串,内层循环统计字符频次。单层循环扩展右指针,内层循环收缩左指针。
适用场景极小规模数据(n ≤ 100)。大规模数据(n ≤ 1e5)。
优点逻辑简单,直接穷举所有可能性。时间复杂度最优,适用于大规模输入。
缺点数据规模大时性能极差(n=1e4时需1e8次操作)。需精确维护哈希表状态(如count增减逻辑)。

相关文章:

  • 【QT:控件】
  • 42、【OS】【Nuttx】【OSTest】内存监控:堆空间初始化
  • RocketMQ企业应用篇
  • 掌握xtquant:实时行情订阅与数据处理的实战指南
  • Vue 生命周期详解:从创建到销毁的全过程
  • 基于大模型的智能客服搭建
  • 构建高性能企业RAG落地-分块的艺术
  • 看门狗机制
  • Matlab 四分之一车体车辆半主动悬架鲁棒控制
  • 马可·波罗的历史及其对中国的影响
  • 在树莓派上运行 COCO-SSD MobileNet 目标检测:完整指南
  • Django初窥门径-Django REST Framework 基础使用
  • 为什么需要使用十堰高防服务器?
  • 电机控制常见面试问题(十一)
  • JSON 语法详解
  • yolov8训练时报错ValueError: I/O operation on closed file.
  • ollama不安装到c盘,安装到其他盘
  • 使用python反射,实现pytest读取yaml并发送请求
  • python字符串类型
  • 【python web】一文掌握 Flask 的基础用法
  • “五一”假期预计全社会跨区域人员流动量超14亿人次
  • 北京银行一季度净赚超76亿降逾2%,不良贷款率微降
  • 力箭二号火箭成功进行满载起竖试验,计划今年首飞发射轻舟飞船
  • 现场聆听总书记讲话,“00后”博士和大模型CEO都“热血沸腾”
  • 五大国有银行明确将撤销监事会
  • 【社论】人工智能,年轻的事业