力扣热门100题之最小覆盖子串

核心解法:滑动窗口 + 哈希表

思路(4 步走)

  1. 用数组 / 哈希表统计 t 中字符的出现次数

  2. 用左右指针形成滑动窗口

  3. 右指针一直右移,直到窗口包含 t 所有字符

  4. 满足条件后,左指针尽量右移,缩小窗口,记录最小窗口

  5. 两个计数数组

  • 用数组比 HashMap 更快
  • 128 覆盖所有 ASCII 字符
java 复制代码
int[] need[128];   // 记录 t 里每个字符需要多少个
int[] window[128]; // 记录当前窗口里每个字符有多少个
  1. 统计 t 字符数量

比如 t="ABC"need 'A'=1, need 'B'=1, need 'C'=1

java 复制代码
for (char c : t.toCharArray()) need[c]++;
  1. 右指针扩张窗口
  • 右指针一直走
  • 遇到 t 需要的字符,就加入窗口
  • 窗口字符数 = 需要的数量 时,valid++
java 复制代码
while (valid == t.length()) {
    更新最小窗口
    左指针右移
    如果移出的是需要的字符,可能导致 valid--
}
  1. 左指针收缩窗口(最关键)
  • valid == t.length()窗口已经包含 t 所有字符
  • 这时尽量移动左指针缩小窗口,寻找更短的满足条件的窗口
java 复制代码
while (valid == t.length()) {
    更新最小窗口
    左指针右移
    如果移出的是需要的字符,可能导致 valid--
}
  1. 最后返回结果
java 复制代码
return minLen == 无穷大 ? "" : s.substring(start, start+minLen)

核心变量总结

need[]:t 需要的字符数量

window[]:当前窗口字符数量

valid窗口中已经满足数量要求的字符种类数

valid == t.length()窗口满足条件

完整代码实现:

java 复制代码
class Solution {
    public String minWindow(String s, String t) {
        // 用于统计字符串 t 中每个字符需要出现的次数
        int[] need = new int[128];
        // 用于统计当前滑动窗口内,各字符的数量
        int[] window = new int[128];

        // 记录 t 中有多少种【不同的字符】(比如 t="aa" → 只有1种)
        int needUnique = 0;

        // 第一步:统计 t 中所有字符的需求
        for (char c : t.toCharArray()) {
            // 第一次遇到这个字符,才增加种类数
            if (need[c] == 0) {
                needUnique++;
            }
            need[c]++;
        }

        // 滑动窗口左右指针
        int left = 0, right = 0;
        // 记录窗口内已经满足数量要求的【字符种类数】
        int valid = 0;

        // 记录最小窗口的起始位置和长度
        int start = 0;
        int minLen = Integer.MAX_VALUE;

        // 第二步:移动右指针,扩展窗口
        while (right < s.length()) {
            // 当前要加入窗口的字符
            char c = s.charAt(right);
            right++;

            // 如果这个字符是 t 中需要的字符
            if (need[c] > 0) {
                // 窗口中该字符数量 +1
                window[c]++;

                // 如果当前字符的数量【刚好达到需求】
                // 说明这一种字符凑齐了,valid +1
                if (window[c] == need[c]) {
                    valid++;
                }
            }

            // 第三步:当窗口满足条件时(所有字符种类都凑齐了)
            // 开始移动左指针,缩小窗口,寻找更短的子串
            while (valid == needUnique) {
                // 更新最小窗口:如果当前窗口更小,就记录下来
                if (right - left < minLen) {
                    start = left;
                    minLen = right - left;
                }

                // 要移出窗口的字符
                char d = s.charAt(left);
                left++;

                // 如果移出的字符是 t 中需要的字符
                if (need[d] > 0) {
                    // 如果移出前,该字符数量刚好满足需求
                    // 那么移出后就不满足了 → valid -1
                    if (window[d] == need[d]) {
                        valid--;
                    }
                    // 窗口中该字符数量 -1(真正移出)
                    window[d]--;
                }
            }
        }

        // 最后:如果没有找到合法窗口,返回空字符串
        // 否则返回最小窗口子串
        return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
    }
}
相关推荐
爱编程的小新☆9 分钟前
【LeetCode】从递归到 Flood Fill:5 道题吃透 DFS 的选择、回溯与标记
java·算法·leetcode·深度优先·回溯·flood fill
Water_Sunzhipeng14 分钟前
2024牛客暑期多校训练营1
算法
hetao173383714 分钟前
2026-08-09~08-14 hetao1733837 的刷题记录
c++·算法
技术小黑17 分钟前
RNN算法实战系列06 | LSTM 实现糖尿病探索与预测
rnn·算法·lstm
evans在进步19 分钟前
LeetCode 33:搜索旋转排序数组——Java 两阶段二分查找详解
java·python·leetcode
疯狂打码的少年38 分钟前
【数据结构】二叉树的性质(五大性质+计算)
数据结构·笔记·算法
wabs6661 小时前
关于图论【A*算法 | 卡码网127.骑士的攻击的思考】
数据结构·算法·图论·卡码网·广搜的改进版
CIO_Alliance1 小时前
AI认知系列(3)| 数据、算法、算力、场景四要素协同
人工智能·算法·ipaas·系统集成·企业cio联盟·企业级ai化转型
Forever Nore2 小时前
LeetCode 13 罗马数字转整数 - 按规则处理
linux·服务器·leetcode
..Dauntless..2 小时前
手写vector vs std::vector:从功能正确到性能达标
算法