LeetCode 76 最小覆盖子串|JS 滑动窗口标准解法(逐行精讲)

大家好,这篇文章用来记录 LeetCode 76 最小覆盖子串 的 JS 标准解法,这道题是滑动窗口的经典必做题,面试频率极高。

我会直接给出可 AC 代码,并逐行详细解释,方便自己复习也分享给大家。

题目简介

给两个字符串 st,找出 s包含 t 所有字符的最短子串

如果没有,返回空字符串 ""


完整可提交代码

javascript 复制代码
var minWindow = function(s, t) {
    const need = {};
    const window = {};
    let valid = 0;
    let left = 0, right = 0;
    let start = 0, len = Infinity;

    // 统计 t 中每个字符需要的数量
    for (const c of t) {
        need[c] = (need[c] || 0) + 1;
    }
    // 需要凑齐的字符种类数
    const needSize = Object.keys(need).length;

    // 右指针遍历整个字符串
    while (right < s.length) {
        const c = s[right];
        right++;

        // 如果当前字符是我们需要的
        if (need[c]) {
            window[c] = (window[c] || 0) + 1;
            // 某一类字符数量达标,valid+1
            if (window[c] === need[c]) {
                valid++;
            }
        }

        // 当窗口已经满足所有条件,开始收缩左侧
        while (valid === needSize) {
            // 更新最小窗口
            if (right - left < len) {
                start = left;
                len = right - left;
            }

            // 准备移除左指针字符
            const d = s[left];
            left++;

            // 如果是需要的字符,判断是否会破坏 valid
            if (need[d]) {
                if (window[d] === need[d]) {
                    valid--;
                }
                window[d]--;
            }
        }
    }

    // 没有找到返回空,否则返回截取的子串
    return len === Infinity ? "" : s.slice(start, start + len);
};

逐行详细解析

1. 变量定义

javascript 复制代码
const need = {};     // 记录 t 中每个字符需要多少个
const window = {};   // 记录当前窗口里每个字符有多少个
let valid = 0;       // 记录已经"数量达标"的字符种类数
let left = 0, right = 0; // 滑动窗口双指针
let start = 0, len = Infinity; // 记录最终最短子串的起点和长度
  • need:我们要找的字符目标数量
  • window:当前窗口内的字符数量
  • valid核心判断条件,表示有多少种字符已经满足数量要求
  • left/right:窗口左、右边界
  • start/len:保存最优解,避免反复截取字符串

2. 统计目标字符

javascript 复制代码
for (const c of t) {
    need[c] = (need[c] || 0) + 1;
}
const needSize = Object.keys(need).length;
  • 遍历 t,统计每个字符需要多少个
  • needSize一共需要凑齐多少种字符

3. 右指针扩大窗口

javascript 复制代码
while (right < s.length) {
    const c = s[right];
    right++;

    if (need[c]) {
        window[c] = (window[c] || 0) + 1;
        if (window[c] === need[c]) {
            valid++;
        }
    }
  • 右指针一直往右走,扩大窗口
  • 遇到需要的字符 ,就加入 window 计数
  • 当某字符数量刚好达标 时,valid += 1

4. 左指针收缩窗口(核心)

javascript 复制代码
while (valid === needSize) {
    // 更新最小窗口
    if (right - left < len) {
        start = left;
        len = right - left;
    }

    const d = s[left];
    left++;

    if (need[d]) {
        if (window[d] === need[d]) {
            valid--;
        }
        window[d]--;
    }
}
  • valid === needSize,说明当前窗口已经包含了 t 所有字符
  • 这时尽可能缩小窗口,寻找更短的子串
  • 每次移动左指针前:
    • 先更新最小窗口记录
    • 再把左边字符移出窗口
    • 如果移出后导致某字符不满足数量valid--,退出循环

5. 返回结果

javascript 复制代码
return len === Infinity ? "" : s.slice(start, start + len);
  • 如果 len 还是无穷大,说明没找到,返回空串
  • 否则返回记录的最短子串

核心思想总结

这道题的核心就是 滑动窗口 + 哈希计数

  1. 用右指针扩大窗口,直到满足条件
  2. 用左指针收缩窗口,直到不满足条件
  3. 全程记录最小窗口
  4. valid 精准判断窗口是否合法

这套模板可以通杀绝大多数子串滑动窗口题,非常实用。


测试用例

javascript 复制代码
console.log(minWindow("ADOBECODEBANC", "ABC")); // "BANC"
console.log(minWindow("a", "a")); // "a"
console.log(minWindow("a", "aa")); // ""
相关推荐
不正经学生3 小时前
C语言预处理详解:编译器真正动手之前的那些事
c语言·开发语言·算法·面试·bug
ℋᙚᵐⁱᒻᵉ鲸落5 小时前
移动端滑动手势冲突:overflow: auto导致外层横向滑动失效
前端·javascript·css·vue.js·html
毕竟是shy哥5 小时前
计算YOLO数据集中每个类的目标数
算法·yolo·机器学习
M78佐菲5 小时前
Linux学习笔记:TCP协议
linux·笔记·学习·tcp/ip·算法
圣保罗的大教堂6 小时前
leetcode 1406. 石子游戏 III 困难
leetcode
默_笙6 小时前
🎃 前端学了 Next.js,后端该学啥?NestJS 就是 Node 版的蜜雪冰城
前端·javascript
晊晌_h7 小时前
嵌入式从0到精通——数据结构总结[特殊字符]
数据结构·算法·排序算法
我找到地球的支点啦7 小时前
Matlab系列(009) 一CRC循环冗余校验详解
开发语言·数据结构·算法·matlab·信息与通信
罗西的思考7 小时前
【OpenClaw具身硬件】ZeroClaw 源码阅读笔记(3)--- RAG
人工智能·算法·机器学习
এ慕ོ冬℘゜8 小时前
navigator 导航对象 BOM制作方法
javascript