力扣热门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);
    }
}
相关推荐
To_OC4 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode
旖-旎5 小时前
LeetCode 518:零钱兑换||(完全背包)—— 题解
c++·算法·leetcode·动态规划·背包问题
To_OC6 小时前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
delishcomcn6 小时前
AI视觉识别+分切算法:电化铝缺陷检测与裁切一体化解锁
人工智能·算法
触底反弹7 小时前
深入理解大模型采样:Temperature、Top-K、Top-P 的原理与实战
人工智能·算法·面试
雪碧聊技术7 小时前
力扣 LCR 091. 粉刷房子 —— 动态规划入门详解
算法·动态规划
CV-Climber10 小时前
检索技术的实际应用
人工智能·算法
hhzz10 小时前
Tiger AI Platform平台中增加人脸识别功能
图像处理·人工智能·算法·计算机视觉·大模型
从零开始的代码生活_11 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法