【LeetCode】困难题76.最小覆盖子串|python版

118 阅读3分钟

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

注意:

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

  示例 1:

输入: s = "ADOBECODEBANC", t = "ABC"
输出: "BANC"
解释: 最小覆盖子串 "BANC" 包含来自字符串 t 的 'A''B''C'
class Solution:
    def minWindow(self, s: str, t: str) -> str:
        if len(s) < len(t):
            return ""

        # 定义哈希表,用于记录窗口内字符和目标字符串字符
        dic_s=defaultdict(int)
        dic_t=defaultdict(int)

        # 初始化目标字符串的哈希表
        for i in t:
            dic_t[i]+=1

        # 定义滑动窗口的起始和结束
        start, end = 0, 0
        min_len = float('inf')
        min_start = 0
        have = 0
        total = len(t)

        # 滑动窗口进行遍历
        while end < len(s):
            # 扩大窗口,添加字符到哈希表中
            char_end = s[end]
            dic_s[char_end] += 1

            # 如果当前字符满足了目标字符的数量,增加已满足的数量
            if char_end in dic_t and dic_s[char_end]<=dic_t[char_end]:
                have+=1

            # 当所有字符都满足时,尝试缩小窗口
            while have == total:
                # 更新最小窗口
                if end - start + 1 < min_len:
                    min_len = end - start + 1
                    min_start = start

                # 尝试缩小窗口,从左边移动
                char_start = s[start]
                dic_s[char_start] -= 1
                if dic_start in dic_t and dic_s[char_start] < dic_t[char_start]:
                    have -= 1
                start += 1

            # 移动窗口的右端
            end += 1

        # 返回最小覆盖子串
        if min_len == float('inf'):
            return ""
        else:
            return s[min_start:min_start + min_len]



```js

代码思路

  1. 初始化

    • 定义两个哈希表dic_sdic_t,分别用来存储滑动窗口内的字符频率和目标字符串t中的字符频率。
    • 初始化滑动窗口的左右指针startend,以及用于记录最小窗口长度和起始位置的min_lenmin_start
    • 初始化have变量来记录窗口中已经满足t中字符要求的数量,total变量来记录t中字符的总种类数。
  2. 滑动窗口

    • 使用while循环,通过移动窗口的右端end来遍历字符串s
    • 每次循环,将end指向的字符加入到dic_s中,并更新其计数。
    • 如果end指向的字符在dic_t中,并且dic_s中该字符的计数不超过dic_t中的计数,则have加1,表示找到了一个满足条件的字符。
  3. 缩小窗口

    • have等于total,即窗口中包含了t中所有种类的字符时,尝试缩小窗口。
    • 检查是否可以从窗口的左端start移除字符,即检查start指向的字符是否仍然满足条件(即dic_s中该字符的计数是否小于dic_t中的计数)。
    • 如果不满足,则have减1,表示移除了一个满足条件的字符。
    • 如果满足条件,则更新最小窗口的长度和起始位置。
  4. 更新最小窗口

    • 在尝试缩小窗口的过程中,如果发现了一个更小的窗口,则更新min_lenmin_start
  5. 返回结果

    • 循环结束后,如果找到了符合条件的最小窗口,则返回这个窗口的字符串;如果没有找到,则返回空字符串。

示例一的图示遍历过程

FME}A2VDV{X8YXN~8VZDY.png