滑动窗口-LeetCode76. 最小覆盖子串

1、题目描述

https://leetcode-cn.com/problems/minimum-window-substring/

给你一个字符串 S、一个字符串 T 。请你设计一种算法,可以在 O(n) 的时间复杂度内,从字符串 S 里面找出:包含 T 所有字符的最小子串

输入:S = "ADOBECODEBANC", T = "ABC"

输出:"BANC"

  • 如果 S 中不存这样的子串,则返回空字符串 ""。
  • 如果 S 中存在这样的子串,我们保证它是唯一的答案。

2、代码详解

左右指针轮流前进,窗口大小增增减减,窗口不断向右滑动

from collections import Counter
from collections import defaultdict


class Solution:
    def minWindow(self, s, t):
        # 最短子串开始位置和长度
        start = 0
        min_len = float('Inf')

        left, right = 0, 0

        # 两个计数器
        needs = Counter(t)
        # print(needs)  # Counter({'A': 1, 'C': 1, 'B': 1})
        # print(len(needs))  # 3
        window = defaultdict(int)
        # defaultdict(int)在访问的key不存在的时候返回默认值0, 可以减少一次逻辑判断
        # list对应[ ],str对应的是空字符串,set对应set( ),int对应0

        match = 0  # 表示窗口中满足need条件的字符个数

        while right < len(s):

            c1 = s[right]  # 将移入窗口的字符
            if needs[c1] > 0:
                window[c1] += 1  # 如果一个字符进入窗口,应该增加window计数器
                if window[c1] == needs[c1]:  # 发现某个字符在window的数量满足了need的需要,就要更新match
                    match += 1  # 表示有一个字符已经满足要求
            right += 1  # 右移窗口

            # 当match == len(needs)时,说明T中所有字符已经被覆盖,已经得到一个可行的覆盖子串,
            # 现在应该开始"收缩窗口"了,以便得到「最小覆盖子串」
            # 判断左侧窗口是否要收缩
            while match == len(needs):
                if right - left < min_len:
                    # 更新最小子串长度
                    min_len = right - left
                    start = left

                c2 = s[left]  # 将移出窗口的字符
                if needs[c2] > 0:
                    window[c2] -= 1  # 如果一个字符将移出窗口的时候,应该减少window计数器
                    if window[c2] < needs[c2]:
                        match -= 1
                left += 1  # 左移窗口

        return s[start:start + min_len] if min_len != float("Inf") else ""
s = "EBBANCF"
t = "ABC"
S = Solution()
print(S.minWindow(s, t))  # 'BANC'

https://mp.weixin.qq.com/s/ioKXTMZufDECBUwRRp3zaA

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值