LeetCode 热题 100 之 76.最小覆盖子串

此题难度为HARD!

解题思路 💡

这道题是经典的 滑动窗口(双指针) 问题,核心是通过左右指针动态调整窗口大小,在 O (n) 时间复杂度内找到包含 t 所有字符的最短子串。

  1. 统计需求 :用数组记录 t 中每个字符的出现次数(need),并统计需要满足的不同字符数量(required)。

  2. 扩展窗口 :右指针向右移动,将字符加入当前窗口,更新窗口内字符计数(window),当窗口满足所有字符需求时,尝试收缩左指针。

  3. 收缩窗口:左指针向右移动,尽可能缩小窗口,同时保持窗口仍满足所有字符需求,记录最小窗口的起始位置和长度。

  4. 结果返回:遍历结束后,若存在有效窗口则返回最短子串,否则返回空串。

    public class Solution {
    public String minWindow(String s, String t) {
    // 边界条件处理
    if (s == null || t == null || s.length() == 0 || t.length() == 0 || s.length() < t.length()) {
    return "";
    }

    复制代码
         // 统计t中字符的需求次数和需要满足的不同字符数
         int[] need = new int[128]; // 覆盖所有ASCII英文字符
         int required = 0;
         for (char c : t.toCharArray()) {
             if (need[c] == 0) {
                 required++; // 新增一个需要满足的字符
             }
             need[c]++;
         }
    
         int[] window = new int[128]; // 记录当前窗口内字符的出现次数
         int left = 0, right = 0; // 左右指针
         int valid = 0; // 当前窗口中满足need的字符数
         int minLen = Integer.MAX_VALUE; // 最小窗口长度
         int start = 0; // 最小窗口的起始索引
    
         while (right < s.length()) {
             char c = s.charAt(right);
             if (need[c] > 0) { // 仅处理t中需要的字符
                 window[c]++;
                 // 当窗口中该字符的数量达到需求时,valid+1
                 if (window[c] == need[c]) {
                     valid++;
                 }
             }
             right++; // 右指针扩展窗口
    
             // 当窗口满足所有字符需求时,尝试收缩左指针
             while (valid == required) {
                 // 更新最小窗口的长度和起始位置
                 if (right - left < minLen) {
                     minLen = right - left;
                     start = left;
                 }
    
                 // 移动左指针,收缩窗口
                 char d = s.charAt(left);
                 if (need[d] > 0) {
                     // 如果该字符的窗口计数刚好等于需求,收缩后会不满足,valid-1
                     if (window[d] == need[d]) {
                         valid--;
                     }
                     window[d]--;
                 }
                 left++;
             }
         }
    
         // 返回结果:若minLen未更新,说明无有效窗口,返回空串
         return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
     }

    }

复杂度分析 📊

  • 时间复杂度:O (n),n 为 s 的长度。每个字符最多被左右指针各访问一次,无嵌套循环。
  • 空间复杂度:O (1),使用的数组大小固定为 128,与输入规模无关。
相关推荐
二哈赛车手7 小时前
新人笔记---ApiFox的一些常见使用出错
java·笔记·spring
吃好睡好便好7 小时前
在Matlab中绘制横直方图
开发语言·学习·算法·matlab
栗子~~7 小时前
JAVA - 二层缓存设计(本地缓冲+redis缓冲+广播所有本地缓冲失效) demo
java·redis·缓存
YDS8298 小时前
DeepSeek RAG&MCP + Agent智能体项目 —— RAG知识库的搭建和接口实现
java·ai·springboot·agent·rag·deepseek
仰泳之鹅8 小时前
【C语言】自定义数据类型2——联合体与枚举
c语言·开发语言·算法
未若君雅裁9 小时前
MyBatis 一级缓存、二级缓存与清理机制
java·缓存·mybatis
AI人工智能+电脑小能手9 小时前
【大白话说Java面试题 第65题】【JVM篇】第25题:谈谈对 OOM 的认识
java·开发语言·jvm
阿维的博客日记10 小时前
Nacos 为什么能让配置动态生效?(涉及 @RefreshScope 注解)
java·spring
雨辰AI10 小时前
SpringBoot3 + 人大金仓读写分离 + 分库分表 + 集群高可用 全栈实战
java·数据库·mysql·政务
x_yeyue10 小时前
三角形数
笔记·算法·数论·组合数学