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

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增减逻辑)。

http://www.kler.cn/a/588151.html

相关文章:

  • “全志V821:智能玩具的理想之选”——科技赋能,乐趣升级
  • Work【2】:PGP-SAM —— 无需额外提示的自动化 SAM!
  • Mininet 的详细设计逻辑
  • Python----数据分析(Pandas四:一维数组Series的统计计算,分组和聚合)
  • 【JavaEE进阶】-- HTML
  • 射频前端模块(FEM)中的功率放大器(PA):关键作用与优化方法
  • 2025可视掏耳勺VS棉签:哪个挖耳朵更安全高效?
  • Codeforces 158B. Taxi
  • AI 应用开发工程师(Agent方向):打造未来的智能体架构!
  • C语言 —— 浮生百态 生灭有时 - 数组
  • 老牌软件,方便处理图片,量大管饱。
  • 73.HarmonyOS NEXT PicturePreviewImage组件深度剖析:高级功能扩展与性能优化策略(三)
  • 【大模型实战篇】使用GPTQ量化QwQ-32B微调后的推理模型
  • 破局者登场:中国首款AI原生IDE Trae深度解析--开启人机协同编程新纪元
  • 图——表示与遍历
  • Python文件管理
  • 神聖的綫性代數速成例題5. 矩陣運算的定義、轉置的性質、方陣多項式的概念
  • Arduino示例代码讲解:ArduinoISP
  • Spring AI整合DeepSeek、Ollama本地大模型
  • 【Git】--- 初识Git Git基本操作