给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。
示例:
输入: s = "ADOBECODEBANC", t = "ABC"
输出: "BANC"
说明:
- 如果 S 中不存这样的子串,则返回空字符串 “”。
- 如果 S 中存在这样的子串,我们保证它是唯一的答案。
【困难】
【分析】滑动窗口法。
外循环 right
内循环 left
当外循环循环到count==count_n and left<=right时,才进内循环
res=(start-end+1的长度,left,right)
dict_t 记录t中各字母出现的次数
count_n 记录t中不重复字母的个数 ,比如t=“abcdd”,count_n=4
字符char → 先对right外循环
dic_window 记录窗口内该字母出现的次数
count 记录 如果字母出现的次数一旦达到dict_t中满足的情况时+1(当count记录的次数等count_n时,说明出现一段窗口满足总情况了。进入内循环再作处理)
进入内循环,对大窗口进行收缩:
char → 对left内循环
end记录相应right的char在s中的下标
start记录相应left的char在s中的下标
如果窗口长度小于已知记录的长度,则刷新记录res:(start-end+1,start,end)
dic_window[char]-1 窗口向内收缩
窗口收缩时同时记录count :当dic_window[char] < dict_t[char]时
当count!=count_n and left>right时,跳出内循环,此时res已经记录下符合题意的最小长度的end-start+1了。
然后再作外循环…
总体思路: 先对right作循环当窗口满足覆盖t的字串时,进入内循环对left作循环,窗口向内收缩找到最小长度的覆盖子串。
from collections import Counter
class Solution(object):
def minWindow(self, s, t):
"""
:type s: str
:type t: str
:rtype: str
"""
if not t or not s:
return ""
if len(t)>len(s):
return ""
dic_t=Counter(t)
count_n=len(dic_t)
s_lst=[]
for i,char in enumerate(s):
if char in t:
s_lst.append((i,char))
res=float("inf"),0,0
left,right=0,0
dic_window={}
count=0
while right<len(s_lst):
char=s_lst[right][1]
dic_window[char]=dic_window.get(char,0)+1
if dic_window[char]==dic_t[char]:
count+=1
while left<=right and count==count_n:
char=s_lst[left][1]
start=s_lst[left][0]
end=s_lst[right][0]
if end-start+1<res[0]:
res=end-start+1,start,end
dic_window[char]-=1
if dic_window[char]<dic_t[char]:
count-=1
left+=1
right+=1
return s[res[1]:res[2]+1] if res[0]!=float("inf") else ""
注:统计字符出现的个数,返回字典:
from collections import Counter
t="abac"
dic_t=Counter(t)
t="abac"
dic_t={}
for i in t:
dic_t[i]=dic_t.get(i,0)+1
注2:一开始也想到说把t中的单词凡是在中出现的位置取出来,但是没有联想到滑窗的方法,一开始也只是取出来的位置放在一个dict中,这样应该也能做出来,以后可以想想怎么做:
s = "ADOBECODEBANC"; t = "ABC"
from collections import defaultdict
dic_s=defaultdict(list)
for i,char in enumerate(s):
if char in t:
dic_s[char].append(i)
dic_s=defaultdict(list, {‘A’: [0, 10], ‘B’: [3, 9], ‘C’: [5, 12]}),这个或者可以用最小路径来做?