力扣热门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);
    }
}
相关推荐
汀、人工智能1 小时前
[特殊字符] 第102课:添加与搜索单词
数据结构·算法·均值算法·前缀树·trie·添加与搜索单词
汀、人工智能1 小时前
07 - 字典dict:哈希表的Python实现
数据结构·算法·数据库架构·哈希表的python实现
oG99bh7CK2 小时前
高光谱成像基础(六)滤波匹配 MF
人工智能·算法·目标跟踪
汀、人工智能2 小时前
04 - 控制流:if/for/while
数据结构·算法·链表·数据库架构··if/for/while
努力学习的小廉2 小时前
我爱学算法之——动态规划(四)
算法·动态规划
北顾笙9802 小时前
day15-数据结构力扣
数据结构·算法·leetcode
AI成长日志3 小时前
【GitHub开源项目专栏】黑客松项目架构模式解析:微服务、事件驱动与Serverless实战
算法
人道领域3 小时前
【LeetCode刷题日记:24】两两交换链表
算法·leetcode·链表
北顾笙9803 小时前
day16-数据结构力扣
数据结构·算法·leetcode