76. Minimum Window Substring (最小覆盖子串 Hard)
题目描述:
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
思路记录:
利用滑动窗口,设置两个指针分别指向滑动窗口的首尾位置。
左右指针分别用来缩小和扩展窗口,左指针初始为0,右指针从起始位置开始遍历字符串。
当滑动窗口中包含了所有的t中的目标字符,j停止扩展,开始向右移动i,收缩窗口,找到包含t中所有字符的最小滑动窗口,此时j-i+1为窗口长度;继续将i向右移动一位,然后重复上述步骤,最后长度的最小值就是要求的结果。
判断滑动窗口是否包含了t的所有元素?
通过字典need来表示滑动窗口中还需要的各元素的数量,只要某个元素包含在滑动窗口中,就在need中对应的元素的数值-1,移除元素时,need中对应数值加1;
初始时need中的元素为t中每个元素,且对应的需要数量全为1.
如果是负数则代表这个元素是多余的,数量为0时表示刚刚好。
如果当need中所有元素的数量都小于等于0时,表示当前滑动窗口不再需要任何元素。
再额外设置一个neednum,代表滑动窗口中所需元素的总数,当遍历到在t中的一个元素c时,need[c]-=1,neednum-=1,这样当neednum==0时,即滑动窗口中包含了t的所有元素。
注:只有当need[c]>0,neednum才减1。防止添加重复的t中的元素造成减1。
代码:
from collections import defaultdict
class Solution:
def minWindow(self, s: str, t: str) -> str:
need = defaultdict(int)
for c in t:
need[c] += 1
i = 0
neednum = len(t)
res=(0,float('inf')) #记录起点终点
for j,c in enumerate(s):
if need[c] > 0:
neednum -= 1
need[c] -= 1 #遍历到每个元素都需要减1
if neednum == 0:
while True:
c = s[i] #从i指向的位置开始
if need[c] == 0: #表明当前元素为第一个处于t中的元素
break
need[c] += 1
i += 1 #i右移
if j - i < res[1] - res[0]:
res = (i, j)
need[s[i]] += 1 #i所处的位置是需要的第一个位置的元素
neednum += 1
i += 1 #i向后移动一位
return "" if res[1]>len(s) else s[res[0]:res[1]+1]
参考:
力扣题解作者:https://leetcode-cn.com/u/mcdull0921/