【每日算法】最小覆盖子串

题目描述


这是 LeetCode 上的 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 的子串中,
因此没有符合条件的子字符串,返回空字符串

提示:

1 <= s.length, t.length <= 10^5
s 和 t 由英文字母组成

分析题目要求

要求在字符串s中截取一段s1,使得包括字符串t中的所有字符,然后s1又得是最小的。

怎样截取字符串并且都包括t中的所有字符呢?
定义一个窗口的左右边界(i,j),res=(0,无穷大)
不断的扩大j,找到s[i:j]包含t中的所有字符,记录res=min(res,s[i':j])
然后不断的缩小i,使得缩小后的i仍然满足s[i':j]包含t,
然后s[i':j]再与res进行比较,res=min(res,s[i':j])

其中有一个难点就是怎么判断s[i:j]是否包含t的所有字符呢?先想到O(1)复杂度的hash和set,但是t里面有重复的字符,所以只能用hash去存储记录
dic里面存储t的字符出现的情况,当dic里记录 t的字符都为0时,此时窗口刚好包括了字符串t中的所有字符,为了快速判断dic里面的所有字符都为0,则需要一个变量保存字符串t的长度,dic的某个字符-1时,则这个临时变量也跟着减1

代码实现

import collections
class Solution(object):
    def minWindow(self, s, t):
        #定义返回的结果坐标
        res=(0,float('inf'))#0到下无穷
        i=0#定义窗口的左右边界
        need=collections.defaultdict(int)#定义记录需要字符的
        needCount=len(t)#所需字符的个数
        for c in t:
            need[c]+=1
        for j,v in enumerate(s):
            #向右扩大窗口,如果是需要的则个数减1
            if need[v]>0:
                needCount-=1
            need[v]-=1
            if needCount==0:#所需的字符都找到了,则在缩小窗口,使窗口最小,但又包括所需的字符
                while need[s[i]]<0:#<0是不需要的字符
                    need[s[i]]+=1
                    i+=1#向左移动
                if res[1]-res[0]>j-i:#替换为小的
                    res=(i,j)
                #在向左移动一个字符,使期不满足,继续向右移动,找更小的
                needCount+=1
                need[s[i]]+=1
                i+=1
        return "" if res[1]>len(s) else s[res[0]:res[1]+1]
posted @ 2021-08-02 14:05  Hitechr  阅读(280)  评论(0)    收藏  举报