LeetCode 76. 最小覆盖子串(Minimum Window Substring)

LeetCode 76. 最小覆盖子串(Minimum Window Substring)

✅ 本题难度:困难

✅ 考察点:滑动窗口 / 哈希表 / Java 包装类陷阱


🔗 题目链接

👉 https://leetcode.com/problems/minimum-window-substring/


📖 题目描述

给定字符串 s 和 t,请在 s 中找出包含 t 所有字符的最小子串。

示例

复制代码
输入:
s = "ADOBECODEBANC"
t = "ABC"

输出:
"BANC"

说明

  • 如果 s 中不存在这样的子串,返回空字符串 ""
  • t 中可能包含重复字符

💡 解题思路(滑动窗口)

核心思想

使用 双指针 + 哈希表 维护一个滑动窗口:

  • need:记录 t 中每个字符需要的次数
  • window:记录当前窗口中每个字符出现的次数
  • scnt:当前窗口中已经满足 need 要求的字符种类数
  • tcnt:目标字符种类数

算法流程

  1. 统计 t 中字符频次 → need
  2. 初始化双指针 l = 0, r = 0
  3. 右指针 r 向右扩展窗口
    • 若字符属于 t,更新 window
    • 若某个字符数量达到 need,scnt++
  4. 当 scnt == tcnt:
    • 尝试收缩左指针
    • 更新最小窗口
  5. 返回最小窗口子串

✅ AC 代码(Java)

java 复制代码
class Solution {
    public String minWindow(String s, String t) {
        char[] S = s.toCharArray();
        HashMap<Character, Integer> window = new HashMap<>();
        HashMap<Character, Integer> need = new HashMap<>();

        // 统计 t 中字符频次
        for (char ch : t.toCharArray()) {
            need.put(ch, need.getOrDefault(ch, 0) + 1);
        }

        int tcnt = need.size();     // 目标字符种类数
        int scnt = 0;               // 当前满足条件的字符种类数
        int cur = 0;                // 最小窗口起点
        int reslen = Integer.MAX_VALUE;

        int l = 0, r = 0;

        while (r < s.length()) {
            char cr = S[r];
            if (need.containsKey(cr)) {
                window.put(cr, window.getOrDefault(cr, 0) + 1);
                // ✅ 必须用 equals,不能用 ==
                if (window.get(cr).equals(need.get(cr))) {
                    scnt++;
                }
            }

            // 窗口满足条件,开始收缩
            while (scnt == tcnt) {
                if (r - l + 1 < reslen) {
                    reslen = r - l + 1;
                    cur = l;
                }

                char cl = S[l];
                if (need.containsKey(cl)) {
                    window.put(cl, window.get(cl) - 1);
                    // ✅ 字符数量不足
                    if (need.get(cl) > window.get(cl)) {
                        scnt--;
                    }
                }
                l++;
            }
            r++;
        }

        return reslen == Integer.MAX_VALUE ? "" : s.substring(cur, cur + reslen);
    }
}

⏱ 复杂度分析

项目 复杂度
时间复杂度 O(n)
空间复杂度 O(字符集) ≈ O(128)

✅ 每个字符最多进出窗口一次


⚠️ 注意事项(非常重要)

1️⃣ Integer 比较必须用 equals

❌ 错误:

java 复制代码
window.get(c) == need.get(c)

✅ 正确:

java 复制代码
window.get(c).equals(need.get(c))

📌 原因 :

Integer 仅在 [-128, 127] 有缓存,超过会新建对象,== 会失效。


2️⃣ 必须先更新答案,再收缩窗口

java 复制代码
if (r - l + 1 < reslen) {
    reslen = r - l + 1;
    cur = l;
}

否则会错过最优解。


3️⃣ HashMap value 可能为 null

  • 使用 getOrDefault
  • 避免 NullPointerException

4️⃣ 返回 substring 时注意区间

java 复制代码
s.substring(cur, cur + reslen)

✅ 左闭右开,符合 Java 规范


🧠 面试加分点

  • 明确说出 滑动窗口收缩条件
  • 指出 Integer == 的坑
  • 提到 时间复杂度 O(n)
  • 能现场手写出 AC 版本

✅ 总结一句话

滑动窗口 + 哈希表统计频次,Integer 比较一定用 equals,这是本题 100% AC 的关键。

相关推荐
苏打豆32 分钟前
CRISP源码阅读——基于ROS2力矩反馈控制器与速度加速度零空间
c++·线性代数·算法·矩阵·机器人
蛋蛋的就会顺顺的1 小时前
hot100——矩阵
java·数据结构·算法·leetcode·力扣
老歌老听老掉牙1 小时前
麻花钻切屑形态演变的力学机制与临界条件分析
python·算法·钻头
zhangfeng11332 小时前
国产GPU/AI算力芯片现状(修订完整版 · 截至2026年9月
人工智能·算法·ai编程·npu
学代码的CJY2 小时前
从代码出发理解时间复杂度与空间复杂度
数据结构·算法
白帽攻防录2 小时前
SRC 挖洞:WSO2 JWT 算法混淆绕过深度复盘,CVE-2026-5430 不支持的算法怎么变成管理员
网络·算法·安全·网络安全·jwt
小O的算法实验室3 小时前
IEEE TEVC,基于精确与DQN群智能调度方法用于多目标异构USV
算法
字节跳动的猫4 小时前
LikeShop 积分体系全链路改造:获取规则、订单抵扣与积分商品兑换二开
运维·数据结构
可乐ea4 小时前
AI Agent 工具调用准确性评测:选择错误与参数错误分开测
大数据·人工智能·算法·大模型·工具调用·ai智能体·agent评测
上位机妹子4 小时前
C 语言 数组删除指定元素(快慢指针法)
c语言·数据结构·算法