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 的关键。

相关推荐
小豆庄8 分钟前
Mac 上给视频人脸打码:本地工具的依赖、追踪与推理管线
算法·视觉检测·视频·敏捷流程·纹理贴图
星夜离尘5624 分钟前
MATLAB 工程实验:从相邻块均值手写重叠 Allan 偏差,数清有效项
算法·matlab·均值算法
careathers1 小时前
【数据结构】从堆到 PriorityQueue:手写一个优先级队列
数据结构
y1su3 小时前
Leetcode 字符串模板
java·数据结构·算法·leetcode·职场和发展·动态规划
residual_fan3 小时前
船用柴油机动态机动工况故障诊断:控制感知仿射网络(CAAN)的技术实现
人工智能·算法·数据挖掘·数据分析
其实防守也摸鱼4 小时前
Cylab在线靶场——CTF中的通用技能
linux·数据库·学习·算法·靶场·ctf·学习网络安全
蓝悦无人机4 小时前
《Planning algorithms》读书笔记——第8章 反馈运动规划
算法·读书笔记·反馈运动规划
RaaS1004 小时前
Agent Skills 进了 Linux Foundation:2.8 亿次安装,但装 skill 还没有安全规范
人工智能·算法·架构
CV爱数码4 小时前
CT 重建从零开始(五):ASTRA Toolbox 上手——几何、投影器与算法
图像处理·算法·计算机视觉·ct
TunerT_TQ4 小时前
超立方体Ramsey(openai/math 家族171)H11攻坚日志|D60–D69:Star分组重数、二幂坐标群、奇偶入射语义与Site‑Level候选计数形式化闭环
算法