题目链接

题目描述

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

  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

    示例

    示例1:

    输入:s = “ADOBECODEBANC”, t = “ABC” 输出:“BANC”

提示

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

    思路

    滑动窗口

    维护一个窗口 start, end ,进行如下操作:
  1. 移动 end 扩展窗口,直到包含 t 中所有字符。
  2. 移动 start 缩小窗口,直到包含所有元素的临界点,即再移动就会不符合要求。
  3. 继续移动 start 一次,重复步骤1。

使用哈希表辅助:
维护一个字典 count 来记录 t 中所有字符及其个数。
在遍历过程中,将相应的字符 count 值减一,若该字符不在 t 中,则 count 值会小于0。这样以来,count 值若为负数,则表示该字符是不需要的。
优化:
维护一个变量 totalLen 来记录当前状态所需要的字符的个数,当 totalLen == 0 时,表示当前窗口已经包含 t 所有元素,而不是去遍历字典。

题解

  1. class Solution:
  2. def minWindow(self, s: str, t: str) -> str:
  3. count = collections.defaultdict(int)
  4. for c in t:
  5. count[c] += 1
  6. totalLen = len(t)
  7. n = len(s)
  8. start, end = 0, 0
  9. ans = (0, n)
  10. while end < n:
  11. if count[s[end]] > 0:
  12. totalLen -= 1
  13. count[s[end]] -= 1
  14. if totalLen == 0:
  15. while count[s[start]] < 0:
  16. count[s[start]] += 1
  17. start += 1
  18. ans = (start, end) if end - start < ans[1] - ans[0] else ans
  19. count[s[start]] += 1
  20. totalLen += 1
  21. start += 1
  22. end += 1
  23. return '' if ans[1] == n else s[ans[0]:ans[1] + 1]

复杂度分析

  • 时间复杂度:0076-最小覆盖子串 - 图1
  • 空间复杂度:0076-最小覆盖子串 - 图2