• 寻找最小覆盖子串 - LeetCode 76


    寻找最小覆盖子串 - LeetCode 76

    LeetCode76. 最小覆盖子串
    给定一个字符串 s 和一个字符串 t,我们的任务是找到 s 中包含 t 所有字符的最小子串。如果找不到,返回空字符串。

    问题背景

    这个问题实际上是滑动窗口(Sliding Window)类型的问题,通常用于在字符串中查找满足一些条件的子串。在该问题中,我们要找到一个包含 t 所有字符的最小子串。

    相关知识

    在解决这个问题之前,让我们了解一些相关的知识点。

    滑动窗口

    滑动窗口是一种经典的算法思想,通常用于解决一些字符串和数组相关的问题。它通过维护一个子数组或子串,通过左右边界的移动,来寻找符合某种条件的子数组或子串。

    滑动窗口算法的一般步骤如下:

    1. 初始化左右指针 leftright,通常都指向数组的第一个元素。
    2. 移动右指针 right,扩大窗口,直到满足某种条件,停止。
    3. 移动左指针 left,缩小窗口,直到不满足条件,停止。
    4. 重复步骤2和步骤3,直到遍历完整个数组。

    哈希表

    哈希表(Hash Table)是一种非常常见的数据结构,用于存储键-值对(Key-Value Pairs)。它通过哈希函数将键映射到对应的位置,从而实现了快速的查找和插入操作。

    问题介绍

    给定字符串 st,我们要找到 s 中包含 t 所有字符的最小子串。如果不存在这样的子串,返回空字符串。

    问题示例

    让我们通过一些示例来更好地理解这个问题。

    示例 1

    输入:

    s = "ADOBECODEBANC", t = "ABC"
    
    • 1

    输出:

    "BANC"
    
    • 1

    解释:

    最小覆盖子串 “BANC” 包含来自字符串 t 的 ‘A’、‘B’ 和 ‘C’。

    示例 2

    输入:

    s = "a", t = "a"
    
    • 1

    输出:

    "a"
    
    • 1

    解释:

    整个字符串 s 就是最小覆盖子串。

    示例 3

    输入:

    s = "a", t = "aa"
    
    • 1

    输出:

    ""
    
    • 1

    解释:

    t 中有两个字符 ‘a’,但 s 中不存在符合条件的子字符串,因此返回空字符串。

    解题思路

    为了解决这个问题,我们可以使用滑动窗口算法。我们需要维护两个指针 leftright,分别表示窗口的左边界和右边界,以及一个哈希表 need 来记录字符串 t 中每个字符的出现次数。

    具体步骤如下:

    1. 初始化指针 leftright,以及哈希表 need
    2. 从左到右移动右指针 right,扩大窗口,如果 s[right]t 中的字符,更新哈希表 need
    3. 当窗口包含 t 中所有字符时,移动左指针 left,缩小窗口,更新 need 和记录结果。
    4. 重复步骤2和步骤3,直到遍历完整个字符串 s

    让我们来看一下代码实现,同时加入注释以更好地理解每一步。

    class Solution:
        def minWindow(self, s: str, t: str) -> str:
            if len(s) < len(t):
                return ""  # 如果s比t短,无法包含t的所有字符,直接返回空字符串
            
            need = collections.defaultdict(int)  # 创建哈希表用于记录t中每个字符的出现次数
            for c in t:
                need[c] += 1  # 初始化need哈希表
            
            needCnt = len(t)  # 需要的字符总数
            left = 0  # 滑动窗口的左指针
            res = (0, float('inf'))  # 记录结果,初始窗口范围为正无穷大
            
            for right, c in enumerate(s):
                if need[c] > 0:
                    needCnt -= 1  # 当s[right]是t中字符,needCnt减少
                need[c] -= 1  # 更新need哈希表
                
                if needCnt == 0:  # 当needCnt为0,表示窗口包含了t的所有字符
                    while True:
                        c = s[left]
                        if need[c] == 0:
                            break
                        need[c]
    
     += 1  # 移动左指针,缩小窗口,同时更新need哈希表
                        left += 1
                    
                    if right - left < res[1] - res[0]:  # 更新最小窗口范围
                        res = (left, right)
                    
                    need[s[left]] += 1  # 左指针右移,需要的字符加1
                    needCnt += 1  # needCnt加1,窗口不再包含t的所有字符
                    left += 1  # 左指针右移
            
            return '' if res[1] > len(s) else s[res[0]:res[1]+1]  # 返回最小覆盖子串
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    时间和空间复杂度

    • 时间复杂度:O(N),其中 N 为字符串 s 的长度。我们遍历字符串 s 一次,同时使用双指针维护滑动窗口。
    • 空间复杂度:O(K),其中 K 为字符串 t 的长度。哈希表 need 最多包含 t 中所有不同字符的出现次数。

    结论

    通过使用滑动窗口算法和哈希表,在时间复杂度为 O(N) 的情况下,我们成功找到了字符串 s 中包含字符串 t 所有字符的最小子串。这是一个经典的算法问题,也是一个非常重要的技巧。希望这篇博客对你有所帮助,让你更好地理解和掌握这一技术。

  • 相关阅读:
    [附源码]SSM计算机毕业设计餐厅卫生安全系统JAVA
    ​标签体系、用户画像、用户分群的区别?​
    双指针算法
    C++初阶(list容器+模拟实现)
    Python爬虫实战:抓取和分析新闻数据与舆情分析
    在 win11 下搭建并使用 ubuntu 子系统(同时测试 win10)——(附带深度学习环境搭建)
    全志T113 开发QT播放器导入libcedarc遇到问题
    Qt6开发的网络通信工具(支持TCP和UDP)
    Deep Learning(1)
    管理经济学--重点
  • 原文地址:https://blog.csdn.net/Geek_/article/details/133971332