【LeetCode刷题】最小覆盖字串

给定两个字符串 st,长度分别是 mn,返回 s 中的 最短窗口 子串 ,使得该子串包含 t 中的每一个字符(包括重复字符 )。如果没有这样的子串,返回空字符串""

测试用例保证答案唯一。

示例 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 的子串中,
因此没有符合条件的子字符串,返回空字符串。

提示:

  • m == s.length
  • n == t.length
  • 1 <= m, n <=
  • st 由英文字母组成

解法思路

  1. 统计目标字符频率 :用字典 need 记录字符串 t 中每个字符的出现次数。
  2. 滑动窗口遍历 :用左右指针维护滑动窗口,右指针先扩大窗口,直到窗口包含 t 的所有字符;再移动左指针缩小窗口,寻找最小满足条件的子串。
  3. 验证窗口有效性 :用变量 valid 记录窗口中满足 need 要求的字符种类数,当 valid 等于 need 的长度时,窗口满足条件。
  4. 记录最小窗口:在窗口满足条件时,持续更新最小窗口的起始位置和长度。

Python 代码:

python 复制代码
from collections import defaultdict


class Solution:
    def minWindow(self, s: str, t: str) -> str:
        """
        寻找字符串s中包含字符串t所有字符的最小覆盖子串
        :param s: 源字符串
        :param t: 目标字符串(需要包含的所有字符)
        :return: 满足条件的最小子串,无则返回空字符串
        """
        # 边界条件1:目标字符串t为空,直接返回空
        if not t:
            return ""
        # 边界条件2:源字符串s比t短,不可能包含,返回空
        if len(s) < len(t):
            return ""

        # 统计t中各字符的需求次数(key:字符,value:需要的次数)
        need = defaultdict(int)
        for c in t:
            need[c] += 1

        # 滑动窗口内的字符统计(记录窗口中各字符的出现次数)
        window = defaultdict(int)
        left = right = valid = 0  # valid:窗口中满足"次数达标"的字符种类数
        start = 0  # 最小窗口的起始索引(最终结果的起始位置)
        min_len = float('inf')  # 最小窗口的长度(初始化为无穷大)

        # 右指针遍历,扩大窗口
        while right < len(s):
            # 取出当前右指针指向的字符,然后右指针右移
            current_char = s[right]
            right += 1

            # 若当前字符是t需要的,更新窗口内的统计
            if current_char in need:
                window[current_char] += 1
                # 当窗口内该字符的数量 == 需求数量时,该字符达标,valid+1
                if window[current_char] == need[current_char]:
                    valid += 1

            # 当窗口满足所有字符需求(valid等于需要的字符种类数),尝试缩小左窗口
            while valid == len(need):
                # 更新最小窗口的信息(如果当前窗口更短)
                current_window_len = right - left
                if current_window_len < min_len:
                    start = left  # 记录最小窗口的起始位置
                    min_len = current_window_len  # 更新最小长度

                # 取出左指针指向的字符,准备移出窗口
                remove_char = s[left]
                left += 1  # 左指针右移,缩小窗口

                # 若移出的字符是t需要的,更新窗口统计和valid
                if remove_char in need:
                    # 若移出前该字符刚好达标,移出后不再达标,valid-1
                    if window[remove_char] == need[remove_char]:
                        valid -= 1
                    # 窗口内该字符的计数-1
                    window[remove_char] -= 1

        # 最终判断:若min_len仍为无穷大,说明无满足条件的窗口,否则返回子串
        return "" if min_len == float('inf') else s[start:start + min_len]


# ------------------- 测试用例 -------------------
if __name__ == "__main__":
    solution = Solution()

    # 测试用例1:基础场景
    s1 = "ADOBECODEBANC"
    t1 = "ABC"
    print(f"测试用例1结果:{solution.minWindow(s1, t1)}")  # 预期输出:"BANC"

    # 测试用例2:t包含重复字符
    s2 = "a"
    t2 = "a"
    print(f"测试用例2结果:{solution.minWindow(s2, t2)}")  # 预期输出:"a"

    # 测试用例3:无满足条件的子串
    s3 = "a"
    t3 = "aa"
    print(f"测试用例3结果:{solution.minWindow(s3, t3)}")  # 预期输出:""

    # 测试用例4:t为空
    s4 = "abc"
    t4 = ""
    print(f"测试用例4结果:{solution.minWindow(s4, t4)}")  # 预期输出:""

    # 测试用例5:s和t完全一致
    s5 = "abcdef"
    t5 = "abcdef"
    print(f"测试用例5结果:{solution.minWindow(s5, t5)}")  # 预期输出:"abcdef"

LeetCode提交代码:

python 复制代码
class Solution:
    def minWindow(self, s: str, t: str) -> str:
        from collections import defaultdict
        # 统计t中各字符的需求次数
        need = defaultdict(int)
        for c in t:
            need[c] += 1
        
        # 滑动窗口内的字符统计
        window = defaultdict(int)
        left = right = valid = 0  # valid:满足需求的字符种类数
        start = 0  # 最小窗口的起始索引
        min_len = float('inf')  # 最小窗口的长度
        
        while right < len(s):
            # 右指针右移,扩大窗口
            c = s[right]
            right += 1
            
            # 若当前字符是t需要的,更新窗口统计
            if c in need:
                window[c] += 1
                # 当窗口内该字符的数量满足需求时,valid+1
                if window[c] == need[c]:
                    valid += 1
            
            # 当窗口满足所有字符需求时,尝试左移窗口缩小范围
            while valid == len(need):
                # 更新最小窗口的信息
                current_len = right - left
                if current_len < min_len:
                    start = left
                    min_len = current_len
                
                # 左指针右移,缩小窗口
                d = s[left]
                left += 1
                
                # 若移出的字符是t需要的,更新窗口统计和valid
                if d in need:
                    # 若移出前该字符数量刚好满足需求,移出后不再满足,valid-1
                    if window[d] == need[d]:
                        valid -= 1
                    window[d] -= 1
        
        # 若未找到满足条件的窗口,返回空字符串;否则返回最小子串
        return "" if min_len == float('inf') else s[start:start+min_len]

程序运行截图展示:

总结

题目要求从字符串s中找出包含字符串t所有字符(包括重复字符)的最短子串。采用滑动窗口算法,通过双指针动态调整窗口范围:右指针扩展窗口直至满足条件,左指针收缩窗口以寻找最小解。使用哈希表统计字符频率,并通过valid变量验证窗口有效性。若存在满足条件的子串,返回最小窗口对应的子串;否则返回空字符串。时间复杂度为O(m+n),适用于英文字符串场景。测试用例验证了算法的正确性,包括基础场景、重复字符及无解情况。

相关推荐
Yzzz-F17 小时前
Problem - 2205D - Codeforces
算法
风之所往_17 小时前
Python 3.0 新特性全面总结
python
2401_8822737218 小时前
如何在 CSS 中正确加载本地 JPG 背景图片
jvm·数据库·python
Lucas_coding18 小时前
【Claude Code Router】 Claude Code 兼容 OpenAI 格式 API, Claude code 接入本地部署模型
人工智能·python
测试员周周18 小时前
【AI测试系统】第5篇:从 Archon 看 AI 工程化落地:为什么"确定性编排+AI 弹性智能"是终局?
人工智能·python·测试
智者知已应修善业18 小时前
【51单片机2个按键控制流水灯运行与暂停】2023-9-6
c++·经验分享·笔记·算法·51单片机
Halo_tjn18 小时前
Java Set集合相关知识点
java·开发语言·算法
大飞记Python19 小时前
【2026更新】Python基础学习指南(AI版)——04数据类型
开发语言·人工智能·python
生成论实验室19 小时前
《事件关系阴阳博弈动力学:识势应势之道》第四篇:降U动力学——认知确定度的自驱演化
人工智能·科技·神经网络·算法·架构
AI科技星19 小时前
全域数学·72分册:场计算机卷【乖乖数学】
算法·机器学习·数学建模·数据挖掘·量子计算