欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 焦点 > 最小覆盖子串:解题思路与代码分析

最小覆盖子串:解题思路与代码分析

2025/1/10 7:11:27 来源:https://blog.csdn.net/qq_17405059/article/details/145030883  浏览:    关键词:最小覆盖子串:解题思路与代码分析

最小覆盖子串:解题思路与代码分析

问题描述

在给定的字符串 s 中,找到包含字符串 t 所有字符的最小子串。如果 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 中只有一个字符 'a',因此没有符合条件的子串,返回空字符串。

题目要求:

  • 对于 t 中重复的字符,最小覆盖子串中该字符数量必须不少于 t 中该字符的数量。
  • 最优解的时间复杂度应为 O(m+n),其中 ms 的长度,nt 的长度。

解题思路

此问题可以通过 滑动窗口 技巧来有效解决,使用双指针和哈希表来判断窗口是否包含所有字符。

滑动窗口算法

滑动窗口是一种常用于解决此类“子串”问题的技巧。基本思路是:

  1. 使用两个指针 leftright,分别表示当前窗口的左右边界。
  2. 通过右指针不断扩展窗口,直到窗口包含了所有 t 中的字符。
  3. 当窗口有效时,尝试通过左指针收缩窗口,来获取最小的覆盖子串。

为了跟踪窗口中的字符,我们使用两个哈希表:

  • count_t:存储字符串 t 中字符的频率。
  • count_s:存储当前窗口中字符的频率。

关键点:

  • 窗口中的字符需要包含 t 中所有字符,并且字符的数量要满足 t 中对应字符的频率。
  • 当窗口满足条件时,尝试收缩窗口,更新最小覆盖子串。

代码实现

from collections import Counterclass Solution:def minWindow(self, s: str, t: str) -> str:ans_left, ans_right = -1, len(s)left = 0count_s = Counter()  # 当前窗口中的字符频率count_t = Counter(t)  # 目标字符串 t 中的字符频率# 记录 t 中需要的字符数量required = len(count_t)formed = 0  # 当前窗口满足的字符种类数# 滑动窗口遍历for right, x in enumerate(s):# 将右边字符加入窗口count_s[x] += 1# 如果窗口中的字符数量与 t 中的字符数量匹配,更新 formedif count_s[x] == count_t[x]:formed += 1# 当窗口包含所有 t 中的字符时,尝试收缩左边界while formed == required:if right - left < ans_right - ans_left:ans_left, ans_right = left, right# 收缩窗口,减小窗口左边界count_s[s[left]] -= 1if count_s[s[left]] < count_t[s[left]]:formed -= 1left += 1# 如果找到了符合条件的子串,返回它;否则返回空字符串return "" if ans_left == -1 else s[ans_left:ans_right + 1]

代码解析

  1. 变量初始化

    • ans_leftans_right 用来记录最小覆盖子串的左右边界。
    • count_s 用于存储当前窗口中字符的频率。
    • count_t 用于存储字符串 t 中字符的频率。
    • required 记录 t 中不同字符的数量。
    • formed 记录当前窗口中满足 t 中字符频率要求的字符种类数。
  2. 遍历字符串 s

    • 对于每个字符 x,增加 count_s[x]
    • 如果 count_s[x] 达到 count_t[x],表示窗口中字符 x 的数量满足要求,formed 增加。
  3. 窗口收缩

    • formed == required 时,表示当前窗口已经包含了 t 的所有字符,可以尝试通过左指针收缩窗口。
    • 在收缩过程中,更新最小覆盖子串的边界,并根据 count_s[s[left]] 是否小于 count_t[s[left]] 来判断是否减少 formed
  4. 返回结果

    • 如果找到满足条件的子串,返回其子串;否则返回空字符串。

时间复杂度分析

  • 每个字符至多被访问两次(一次是右指针扩展,另一次是左指针收缩),所以时间复杂度是 O(m+n),其中 ms 的长度,nt 的长度。
  • 因为每个字符的计数操作是常数时间,哈希表的查找和更新操作也是常数时间,所以算法是高效的。

总结

通过滑动窗口技术,我们能够在 O(m+n) 的时间复杂度内找到字符串 s 中涵盖 t 所有字符的最小子串。该方法高效、简洁,且能够处理大规模输入。

这种解法的关键点是巧妙利用哈希表记录字符频率,结合双指针来维护窗口,从而有效地找到符合条件的最小子串。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com