首页 > 技术文章 > 【LeetCode】76. 最小覆盖子串

Curryxin 2022-04-08 17:07 原文

76. 最小覆盖子串

知识点:字符串;滑动窗口

题目描述

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

注意:

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

示例
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"

示例 2:
输入:s = "a", t = "a"
输出:"a"

示例 3:
输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。


解法一:滑动窗口

这其实也是滑动窗口的一道典型题目
刚看题目,最小子串,其实应该自然的想到滑动窗口。 最小,往往都是right向右移动满足条件,寻找可行解,然后left移动,缩小窗口,寻找最优解;
对应到这道题目:
1.right右移,直到当前窗口满足条件,也就是窗口内含有t里的全部的字符

步骤一的难点在于怎么知道窗口内含有t里的全部了,自然的想到可以用哈希表先来统计t里每个字符的数量,然后向右遍历,遇到一个数量就减1.那这时候又有问题,什么时候停止呢,再去遍历一遍哈希表,每个value都为0就停?
总不能每走一步检查一遍吧。所以可以直接使用一个变量,比如needcout来表示我们需要的总数量,注意**是当前窗口内我们需要字符的总数量**当这个数量为0时,代表t里的字符都包括了。
注意这里还有一个小点就是比如我们需要abc,那我们可能刚开始进来两个a,也就是aa,不要把needcount直接减2了,是减1,这个a是多余的,我们并不需要,所以哈希表的value if为负了,其实就表示有多余的元素了。

2.left开始移动,缩小窗口

步骤二无非就几种可能:   
left的元素啥用没有,left继续接着移就行    
left的元素是t里的元素,但是对应的value为负值,证明是多余的,移出去也没事;  
left的元素是t里的元素,对应的value值为0,证明这个很关键,当移出去的时候,我们的窗口就不满足条件了,右边窗口需要继续移动;重复步骤一
from collections import Counter
class Solution:
    def minWindow(self, s: str, t: str) -> str:
        count_table = Counter(t)
        i, j = 0, len(s)
        need_count = len(t)  #当前窗口内需要的全部数量
        left = 0
        for index, cur_str in enumerate(s):
            if cur_str in count_table and need_count > 0:
                if count_table[cur_str] > 0:
                    need_count -= 1
                count_table[cur_str] -= 1

            if need_count == 0:   # 开始收缩
                while True:
                    str_temp = s[left]  #出窗口的元素
                    if str_temp in count_table and count_table[str_temp] == 0:  #找到一个必须的元素后就不能再往出了
                        break
                    elif str_temp in count_table and count_table[str_temp] < 0:
                        count_table[str_temp] += 1
                    left += 1
                if index-left < j-i:
                    i, j = left, index   #记录此时的窗口
                count_table[str_temp] += 1  # 再往外走一个,然后右边开始重新走找满足条件的窗口
                need_count += 1
                left += 1
        return "" if j == len(s) else s[i:j+1]

推荐阅读