16.滑动窗口经典例题:最小覆盖子串(LeetCode 76)算法原理剖析

目录

一、题目解析

二、讲解算法原理

[解法一:暴力枚举 + 哈希表](#解法一:暴力枚举 + 哈希表)

[解法二:滑动窗口 + 哈希表](#解法二:滑动窗口 + 哈希表)

优化:判断条件

三、代码实现


大家好,今天我们来攻克 LeetCode 上的一道经典难题------76. 最小覆盖子串。这道题是滑动窗口算法的典型应用,结合了哈希表来优化判断过程。


一、题目解析

题目: ​ 给你一个字符串 s、一个字符串 t。返回 s中涵盖 t所有字符的最小子串。如果 s中不存在涵盖 t所有字符的子串,则返回空字符串 ""。

注意:

  1. 对于 t中重复字符,我们寻找的子串中该字符数量必须不少于 t中该字符数量。

  2. 如果 s中存在这样的子串,我们保证它是唯一的答案。

示例 1:

  • 输入: ​ s = "ADOBECODEBANC", t = "ABC"

  • 输出: ​ "BANC"

  • 解释: ​ 最小覆盖子串 "BANC"包含来自字符串 t的 'A'、'B'和 'C'。

示例 2:

  • 输入: ​ s = "a", t = "a"

  • 输出: ​ "a"

  • 解释: ​ 整个字符串 s是最小覆盖子串。

示例 3:

  • 输入: ​ s = "a", t = "aa"

  • 输出: ​ ""

  • 解释: ​ t中两个字符 'a'均应包含在 s的子串中,因此没有符合条件的子子串,返回空字符串。


二、讲解算法原理

解法一:暴力枚举 + 哈希表

解法二:滑动窗口 + 哈希表

这是本题的最优解。核心思想是维护一个窗口 [left, right],通过移动左右指针来寻找最小覆盖子串。

  • 核心逻辑:

    1. right 右移: ​ 不断扩大窗口,直到窗口包含了 t中的所有字符。

    2. **left 右移:**​ 在满足覆盖条件的前提下,尝试缩小窗口左边界,以找到最小长度。

优化:判断条件

为了优化每次判断窗口是否覆盖 t的时间复杂度,我们可以引入一个变量 count。

  • 思路: ​ 使用变量 count标记有效字符的种类。

    • 进窗口: ​ 当 hash2[in] == hash1[in]时,count++。

    • 出窗口: ​ 当 hash2[out] == hash1[out]时,count--。

    • 判断条件: ​ 当 count == hash1.size()时,说明窗口已覆盖 t。


三、代码实现

java 复制代码
class Solution 
{
    public String minWindow(String ss, String tt) 
    {
        char[] s = ss.toCharArray();
        char[] t = tt.toCharArray();

        int[] hash1 = new int[128]; // 统计字符串 t 中字符的频次
        int kinds = 0; // 字符串 t 中,有多少种字符
        for(char ch : t)
        {
            if(hash1[ch]++ == 0) kinds++;
        }

        int[] hash2 = new int[128]; // 统计窗口中字符的频次

        int minlen = Integer.MAX_VALUE, begin = -1;
        for(int left = 0, right = 0, count = 0; right < s.length; right++)
        {
            char in = s[right];
            if(++hash2[in] == hash1[in]) count++; // 进窗口 + 维护 count
            
            while(kinds == count) // 判断
            {
                // 更新结果
                if(right - left + 1 < minlen)
                {
                    begin = left;
                    minlen = right - left + 1;
                }
                
                char out = s[left++];
                if(hash2[out]-- == hash1[out]) count--; // 出窗口 + 维护 count
            }
        }
        
        if(begin == -1) return new String();
        else return ss.substring(begin, begin + minlen);
    }
}
相关推荐
j7~1 天前
【穷举、深搜与回溯算法】一棵决策树讲透全排列与子集
数据结构·c++·算法·leetcode·回溯·递归
傅科摆 _ py1 天前
DP,贪心,堆和栈,二分力扣复习
开发语言·python·算法
Shaoshing1 天前
LeetCode100 42.接雨水
java·算法·leetcode
域限奇点访客1 天前
用AI生成问卷的网站怎么选?看题目录入结构、题型映射和生成后的校验
算法
soft_hub11 天前
海外会议怎么用录音APP翻译会议内容
面试·职场和发展
文丑颜不良啊1 天前
LeetCode1261~1280题目解析
java·leetcode
not coder1 天前
一文讲通--从树到红黑树
数据结构·算法
octopus_c1 天前
C++ 入门
开发语言·c++·算法
ZhengEnCi1 天前
2026年10月30日AI早报:Gemini 4 Carbon登顶、DeepSeek融资1055亿、智元机器人上岗实测
人工智能·算法
强哥聊算力1 天前
《算力江湖·Intel帝国往事》第三集:安迪·格鲁夫的铁血时代:Intel为什么能把对手逼到墙角?
运维·人工智能·科技·算法·ai·gpu算力