Minimum Window Substring LT76

Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

Example:

Input: S = "ADOBECODEBANC", T = "ABC"
Output: "BANC"

Note:

  • If there is no such window in S that covers all characters in T, return the empty string "".
  • If there is such window, you are guaranteed that there will always be only one unique minimum window in S.

Idea 1. Sliding window with two pointers. The right pointer to expand the window while fixing the left window and the left pointer to shrink the given window while fixing the right window. At any time only one of these pointer move and the other remains fixed. 经典的滑动窗口的方法, 用左右2各点滑动形成的窗口中找寻符合条件的窗口。这题麻烦的地方是如何快速的判断符合条件的窗口(letterSeen == T.length),包含T的所有字母的最小窗口, 包含T的所有字母的窗口字母个数和T至少一样长。T中可能有重复字母,需要用map来记下每个字母出现的个数。

如何update letterSeen? 

  ++letterSeen if window[right] <= letterT[right] after ++window[right]

  --letterSeen if window[left] < letterT[left] after --window[left]

Time complexity: O(S + T), in the worst case each element is visited twice, once by right pointer, once by the left pointer. (exactly loop time 2 * S + T)

Space complexity: O(T + S), depends on the dictionary size

1.a.建立2个map, 第一个letterT用来记下T中字母出现个数,第二个window记录滑动窗口中字母出现的个数, 判断窗口中出现的字母是不是符合条件的,比如s = "aab", t = "ab", letterT['a' - 'A'] = 1,  当right = 0, window['a'-'A'] = 1 <= 2, T中的字母扫了一个,letterSeen = 1; 当right = 1, window['a'-'A'] = 2 > letterT['a' - 'A'], 扫到的比T中还多,算是多余的,就不能加letterSeen, letterSeen = 1; 当right = 2,window['b'-'A'] = 1 <= letter['b'-'A'], letterSeen = 2 == T.length, "aab"是第一个符合条件的窗口;再固定右边活动左边来找是不是还有更小的,window['a'-'A'] = 1, letterSeen == T.length, "ab"符合条件; 继续右滑,window['a'-'A'] = 0 < T['a' - 'A'], letterSeen = 1 不符合条件。

++letterSeen if window[c-'A'] <= T[c-'A']

Note.

  window[c-'A']用作字母为key的map很方便

      滑动左边不要忘记 ++left

 1 class Solution {
 2     public String minWindow(String s, String t) {
 3         int[] letterT = new int[256];
 4         for(int i = 0; i < t.length(); ++i) {
 5             ++letterT[t.charAt(i) - 'A'];
 6         }
 7         
 8         int[] window = new int[256];
 9         int start = -1;
10         int letterSeen = 0;
11         int minLen = Integer.MAX_VALUE;
12         for(int left = 0, right = 0; right < s.length(); ++right) {
13             int keyRight = s.charAt(right) - 'A';
14             ++window[keyRight];
15             if(window[keyRight] <= letterT[keyRight]) {
16                 ++letterSeen;
17                 while(letterSeen == t.length()) {
18                     if(right - left + 1 < minLen) {
19                         minLen = right - left + 1;
20                         start = left;
21                     }
22                     int keyLeft = s.charAt(left) - 'A';
23                     --window[keyLeft];
24                     if(window[keyLeft] < letterT[keyLeft]) {
25                         --letterSeen;
26                     }
27                     ++left;
28                 }
29             }
30         }
31         
32         if(start == -1) {
33             return "";
34         }
35         return s.substring(start, start + minLen);
36     }
37 }

python

 1 class Solution:
 2     def minWindow(self, s: str, t: str) -> str:
 3         letterT = collections.Counter(t)
 4             
 5         window = collections.defaultdict(int)
 6         left = 0
 7         letterSeen = 0
 8         start = -1
 9         minLen = len(s) + 1
10         for right in range(len(s)):
11             
12             window[s[right]] += 1
13             if window[s[right]] <= letterT[s[right]]:
14                 letterSeen += 1
15                 while letterSeen == len(t):
16                     if right - left + 1 < minLen:
17                         start = left;
18                         minLen = right - left + 1
19                         
20                    
21                     window[s[left]] -= 1
22                     if window[s[left]] < letterT[s[left]]:
23                         letterSeen -= 1
24                 
25                     left += 1
26                     
27         if start == -1:
28             return ""
29         
30         return s[start: start + minLen]

 2.b 只需要一个map letterT, 用右滑动来减字母个数,左滑动来加字母个数,如果左边也扫到尾部,正好左右抵消还原原来的map.

 1 class Solution {
 2     public String minWindow(String s, String t) {
 3         int[] letterT = new int[256];
 4         
 5         for(int i = 0; i < t.length(); ++i) {
 6             ++letterT[t.charAt(i) - 'A'];
 7         }
 8         
 9         int lettersSeen = 0;
10         int minLen = Integer.MAX_VALUE;
11         int start = -1;
12         for(int left = 0, right = 0; right < s.length(); ++right) {
13             --letterT[s.charAt(right) - 'A'];
14             if(letterT[s.charAt(right) - 'A'] >= 0) {
15                 ++lettersSeen;
16                 
17                 while(lettersSeen == t.length()) {
18                     if(right - left + 1 < minLen) {
19                         minLen = right - left + 1;
20                         start = left;
21                     }
22                     ++letterT[s.charAt(left) - 'A'];
23                     if(letterT[s.charAt(left) - 'A'] > 0) {
24                         --lettersSeen;
25                     }
26                     ++left;
27                 }
28             }
29         }
30         
31         if(start == -1) {
32             return "";
33         }
34         return s.substring(start, start + minLen);
35     }
36 }

python:

 1 class Solution:
 2     def minWindow(self, s: str, t: str) -> str:
 3         letterT = collections.Counter(t)
 4         
 5         lettersSeen = 0
 6         start = -1
 7         minLen = len(s) + 1
 8         left = 0
 9         for right in range(len(s)):
10             if s[right] in letterT:
11                 letterT[s[right]] -= 1
12                 if letterT[s[right]] >= 0:
13                     lettersSeen += 1
14                     
15                     while lettersSeen == len(t):
16                         if right - left + 1 < minLen:
17                             minLen = right - left + 1
18                             start = left
19                             
20                         if s[left] in letterT:
21                             letterT[s[left]] += 1
22                             
23                             if letterT[s[left]] > 0:
24                                 lettersSeen -= 1
25                                 
26                         left += 1
27                         
28         if start == -1:
29             return ""
30         
31         return s[start: start+minLen]

猜你喜欢

转载自www.cnblogs.com/taste-it-own-it-love-it/p/10569778.html