力扣滑动窗口两大压轴题:最小覆盖子串 + 滑动窗口最大值(保姆级思路 + 代码详解)

76. 最小覆盖子串

题目链接

76. 最小覆盖子串 - 力扣(LeetCode)

题目描述

给你字符串 s 和字符串 t,请你找出 s 中包含 t 所有字符的最短连续子串,如果没有返回空串。

核心思路

这道题是滑动窗口的经典难题,核心思想:

  1. 用两个哈希表:
    • need:记录t中每个字符需要的数量
    • window:记录当前窗口内字符的数量
  2. 右指针right不断向右扩大窗口
  3. 当窗口完全包含 t 所有字符 时,尝试移动左指针left缩小窗口,寻找最小长度
  4. 全程记录最小窗口的起始位置和长度,最后截取结果

代码实现(逐行注释)

复制代码
class Solution {
    public String minWindow(String s, String t) {
        // 边界判断:空字符串直接返回空
        if (s == null || s.isEmpty() || t == null || t.isEmpty()){
            return "";
        }

        // 记录 t 中字符的需求量
        Map<Character,Integer> need = new HashMap<>();
        // 记录当前窗口内字符的数量
        Map<Character,Integer> window = new HashMap<>();

        int left = 0, right = 0;    // 滑动窗口左右指针
        int strnumber = 0;          // 已匹配成功的字符种类数
        int minlen = Integer.MAX_VALUE;  // 最短子串长度
        int start = 0;              // 最短子串起始位置

        // 初始化 need 哈希表
        for(char c : t.toCharArray()) {
            need.put(c, need.getOrDefault(c, 0) + 1);
        }

        // 右指针移动,扩展窗口
        while(right < s.length()){
            char r = s.charAt(right);
            right++;

            // 如果当前字符在 t 中,更新窗口计数
            if(need.containsKey(r)){
                window.put(r, window.getOrDefault(r, 0) + 1);
                // 该字符数量匹配成功
                if (need.get(r).equals(window.get(r))) {
                    strnumber++;
                }
            }

            // 窗口已完全包含 t 所有字符,开始收缩左边界
            while (strnumber == need.size()){
                // 更新最小窗口
                if (right - left < minlen){
                    start = left;
                    minlen = right - left;
                }

                // 左指针右移,尝试缩小窗口
                char l = s.charAt(left);
                if (window.containsKey(l)){
                    window.put(l, window.get(l) - 1);
                    // 该字符不再满足要求,匹配数减少
                    if (window.get(l) < need.get(l)) {
                        strnumber--;
                    }
                }
                left++;
            }
        }

        // 没有符合条件的子串返回空,否则截取结果
        return minlen == Integer.MAX_VALUE ? "" : s.substring(start, start + minlen);
    }
}

239. 滑动窗口最大值

题目链接

239. 滑动窗口最大值 - 力扣(LeetCode)

题目描述

给你一个数组 nums,有一个大小为 k 的窗口从左端滑到右端,你只能看到窗口内的 k 个数字,返回每个窗口的最大值。

核心思路

这道题不能暴力遍历,否则超时。正确解法:自定义单调队列 + 滑动窗口

核心规则:

  1. 维护一个单调递减队列,队首永远是当前窗口最大值
  2. 加入元素时:比当前元素小的全部弹出,保持队列递减
  3. 弹出元素时:只有要移除的元素 == 队首,才真正弹出
  4. 队首就是当前窗口最大值

代码实现(自定义单调队列 + 逐行注释)

复制代码
// 自定义单调递减队列
class Mydeque{
    Deque<Integer> deque = new LinkedList<>();

    // 弹出元素:判断是否为队首(最大值)
    void poll(int val){
        if(!deque.isEmpty() && val == deque.peek()){
            deque.poll();
        }
    }

    // 添加元素:比当前值小的全部移除,保持单调递减
    void add(int val){
        while(!deque.isEmpty() && val > deque.getLast()){
            deque.removeLast();
        }
        deque.add(val);
    }

    // 获取队首(当前窗口最大值)
    int peek(){
        return deque.peek();
    }
}

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int n = nums.length;
        int len = n - k + 1;
        int[] res = new int[len];  // 存储每个窗口最大值
        int index = 0;

        Mydeque mydeque = new Mydeque();

        // 先把第一个窗口的元素加入队列
        for(int i = 0; i < k; i++){
            mydeque.add(nums[i]);
        }
        res[index++] = mydeque.peek();

        // 开始滑动窗口
        for(int i = k; i < n; i++){
            // 移除窗口左边移出的元素
            mydeque.poll(nums[i - k]);
            // 添加窗口右边新进入的元素
            mydeque.add(nums[i]);
            // 记录当前窗口最大值
            res[index++] = mydeque.peek();
        }

        return res;
    }
}

博客总结

这两道题是滑动窗口最常考的难题,也是面试高频手撕题:

  1. 最小覆盖子串:双哈希表 + 滑动窗口,找最短包含子串
  2. 滑动窗口最大值:自定义单调队列 + 滑动窗口,O (n) 高效求解
相关推荐
无限码力2 小时前
8.26华为OD机试真题 新系统【字符串回文判断】
算法·华为od·华为od机考·华为od机试·华为od上机考试真题·华为od最新机试真题题解·华为od机试真题题库
Tisfy4 小时前
LeetCode 1927.求和游戏:抵消+看最值
java·leetcode·游戏·题解·博弈论
玖玥拾4 小时前
LeetCode 125 验证回文串
算法·leetcode
Asize11 小时前
146. LRU 缓存
算法
Asize11 小时前
543. 二叉树的直径
算法
lemon_sjdk11 小时前
ObjectProperty
java·开发语言·算法
Zentceh11 小时前
AI-ISP在夜视机芯中的应用:从传统ISP到PixelClean全彩夜视的进化
人工智能·科技·算法·计算机视觉·车载系统·视频·智能硬件
xier_ran12 小时前
【infra之路】AWQ 详解:激活感知权重保护,让 W4A16 量化精度超越 GPTQ
线性代数·算法·机器学习·量化·infra
亦皓ai12 小时前
AI时代后端工程(二):AI把代码写得越来越快,我却越来越不敢让它直接开工了
人工智能·算法·机器学习·搜索引擎·transformer
玖玥拾13 小时前
LeetCode 392 判断子序列
笔记·算法·leetcode