**76. Minimum Window Substring 最小覆盖子串

1. 原始题目

给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。

示例:

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

说明:

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

2. 思路

双指针滑动窗口。[i,j]左闭又闭区间表示当前子串。如果当前子串包好含了所有目标字符,则记录当前结果,i右移,并判断右移时是否有目标字符被移出去。否则j继续向右扩展。

3. 实现

 1 class Solution:
 2     def minWindow(self, s: str, t: str) -> str:
 3         if not s: return ''
 4         c = Counter(t)           # 目标串的计数器字典
 5         temp = defaultdict(int)   # 当前子串的字典
 6         i,j = 0,-1       # i,j为左闭又闭区间,表示当前字符串 
 7         len_temp = 0     # 记录当前子串完整包含目标串元素的个数
 8         res=s+'!'        # 初始化结果字符串
 9         while(i<len(s)):         
10             if j+1<len(s) and len_temp<len(c):    # 如果当前串没有完整包含目标串
11                 temp[s[j+1]]+=1                   # 将下一个元素纳入
12                 if temp[s[j+1]] == c[s[j+1]]:     # 如果此时该元素满足了目标串数目的要求,则子串长度加1
13                     len_temp+=1
14                 j+=1                              # 有边界右移
15             elif len_temp==len(c):                # 如果当前串完整包含了目标串
16                 res = res if len(res)<len(s[i:j+1]) else s[i:j+1]    # 先看看是否有更好的解
17                 if s[i] in c and temp[s[i]]<=c[s[i]]:       # 该右移左边界了,看看是否破环了串完整度
18                     len_temp-=1                             # 如果把重要的字符移出去了,长度应该减1
19                 temp[s[i]]-=1                     # 计数相应-1
20                 i+=1                              # 左边界右移 
21             else:
22                 break                             # 都不满足条件则应该break
23            
24         return '' if res==s+s else res 

 

leetcode解题区也有完整python实现:

 1 def minWindow(self, s, t):
 2     """
 3     :type s: str
 4     :type t: str
 5     :rtype: str
 6     """
 7 
 8     if not t or not s:
 9         return ""
10 
11     # Dictionary which keeps a count of all the unique characters in t.
12     dict_t = Counter(t)
13 
14     # Number of unique characters in t, which need to be present in the desired window.
15     required = len(dict_t)
16 
17     # left and right pointer
18     l, r = 0, 0
19 
20     # formed is used to keep track of how many unique characters in t are present in the current window in its desired frequency.
21     # e.g. if t is "AABC" then the window must have two A's, one B and one C. Thus formed would be = 3 when all these conditions are met.
22     formed = 0
23 
24     # Dictionary which keeps a count of all the unique characters in the current window.
25     window_counts = {}
26 
27     # ans tuple of the form (window length, left, right)
28     ans = float("inf"), None, None
29 
30     while r < len(s):
31 
32         # Add one character from the right to the window
33         character = s[r]
34         window_counts[character] = window_counts.get(character, 0) + 1
35 
36         # If the frequency of the current character added equals to the desired count in t then increment the formed count by 1.
37         if character in dict_t and window_counts[character] == dict_t[character]:
38             formed += 1
39 
40         # Try and contract the window till the point where it ceases to be 'desirable'.
41         while l <= r and formed == required:
42             character = s[l]
43 
44             # Save the smallest window until now.
45             if r - l + 1 < ans[0]:
46                 ans = (r - l + 1, l, r)
47 
48             # The character at the position pointed by the `left` pointer is no longer a part of the window.
49             window_counts[character] -= 1
50             if character in dict_t and window_counts[character] < dict_t[character]:
51                 formed -= 1
52 
53             # Move the left pointer ahead, this would help to look for a new window.
54             l += 1    
55 
56         # Keep expanding the window once we are done contracting.
57         r += 1    
58     return "" if ans[0] == float("inf") else s[ans[1] : ans[2] + 1]

 

posted @ 2019-05-03 10:15  三年一梦  阅读(205)  评论(0)    收藏  举报