-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathminimum_window_substring.py
208 lines (161 loc) · 6.47 KB
/
minimum_window_substring.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
"""
Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If there is no such substring, return the empty string "".
The testcases will be generated such that the answer is unique.
A substring is a contiguous sequence of characters within the string.
Example 1:
Input: s = "ADOBECODEBANC", t = "ABC"
Output: "BANC"
Explanation: The minimum window substring "BANC" includes 'A', 'B', and 'C' from string t.
Example 2:
Input: s = "a", t = "a"
Output: "a"
Explanation: The entire string s is the minimum window.
Example 3:
Input: s = "a", t = "aa"
Output: ""
Explanation: Both 'a's from t must be included in the window.
Since the largest window of s only has one 'a', return empty string.
Constraints:
m == s.length
n == t.length
1 <= m, n <= 105
s and t consist of uppercase and lowercase English letters.
Follow up: Could you find an algorithm that runs in O(m + n) time?
"""
# V0
# V0'
# TODO : FIX BELOW
# from collections import Counter
# class Solution(object):
# def check(self, x, y):
# for key in y.keys():
# if x[key] < y[key]:
# return False
# return True
#
# def minWindow(self, s, t):
# if len(t) > len(s):
# return ""
# if len(t) == len(s):
# return s if Counter(s) == Counter(t) else ""
#
# t_cnt = Counter(t)
# s_cnt = Counter()
# tmp = []
# res = []
#
# for i in range(len(s)):
# tmp = []
# for j in range(i,len(s)):
# #print ("i = " + str(i) + " j = " + str(j) + " s_cnt = " + str(s_cnt))
# if s[j] in t:
# #if
# s_cnt[s[j]] += 1
# tmp.append(s[j])
# #if s_cnt == t_cnt:
# if self.check(s_cnt, t_cnt):
# res.append([j-i+1, "".join(tmp)])
# tmp = []
# s_cnt = Counter()
# break
#
# _res = [item for item in res if len(item[1]) >= len(t)]
# _res.sort(key = lambda x : x[0] )
#
# if len(_res) == 0:
# return ""
#
# return _res[0][1]
# V1
# IDEA : SLIDING WINDOW
# https://leetcode.com/problems/minimum-window-substring/solution/
class Solution:
def minWindow(self, s, t):
"""
:type s: str
:type t: str
:rtype: str
"""
if not t or not s:
return ""
# Dictionary which keeps a count of all the unique characters in t.
dict_t = Counter(t)
# Number of unique characters in t, which need to be present in the desired window.
required = len(dict_t)
# left and right pointer
l, r = 0, 0
# formed is used to keep track of how many unique characters in t are present in the current window in its desired frequency.
# 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.
formed = 0
# Dictionary which keeps a count of all the unique characters in the current window.
window_counts = {}
# ans tuple of the form (window length, left, right)
ans = float("inf"), None, None
while r < len(s):
# Add one character from the right to the window
character = s[r]
window_counts[character] = window_counts.get(character, 0) + 1
# If the frequency of the current character added equals to the desired count in t then increment the formed count by 1.
if character in dict_t and window_counts[character] == dict_t[character]:
formed += 1
# Try and contract the window till the point where it ceases to be 'desirable'.
while l <= r and formed == required:
character = s[l]
# Save the smallest window until now.
if r - l + 1 < ans[0]:
ans = (r - l + 1, l, r)
# The character at the position pointed by the `left` pointer is no longer a part of the window.
window_counts[character] -= 1
if character in dict_t and window_counts[character] < dict_t[character]:
formed -= 1
# Move the left pointer ahead, this would help to look for a new window.
l += 1
# Keep expanding the window once we are done contracting.
r += 1
return "" if ans[0] == float("inf") else s[ans[1] : ans[2] + 1]
# V1'
# IDEA : OPTIMIZED SLIDING WINDOW
# https://leetcode.com/problems/minimum-window-substring/solution/
class Solution:
def minWindow(self, s, t):
"""
:type s: str
:type t: str
:rtype: str
"""
if not t or not s:
return ""
dict_t = Counter(t)
required = len(dict_t)
# Filter all the characters from s into a new list along with their index.
# The filtering criteria is that the character should be present in t.
filtered_s = []
for i, char in enumerate(s):
if char in dict_t:
filtered_s.append((i, char))
l, r = 0, 0
formed = 0
window_counts = {}
ans = float("inf"), None, None
# Look for the characters only in the filtered list instead of entire s. This helps to reduce our search.
# Hence, we follow the sliding window approach on as small list.
while r < len(filtered_s):
character = filtered_s[r][1]
window_counts[character] = window_counts.get(character, 0) + 1
if window_counts[character] == dict_t[character]:
formed += 1
# If the current window has all the characters in desired frequencies i.e. t is present in the window
while l <= r and formed == required:
character = filtered_s[l][1]
# Save the smallest window until now.
end = filtered_s[r][0]
start = filtered_s[l][0]
if end - start + 1 < ans[0]:
ans = (end - start + 1, start, end)
window_counts[character] -= 1
if window_counts[character] < dict_t[character]:
formed -= 1
l += 1
r += 1
return "" if ans[0] == float("inf") else s[ans[1] : ans[2] + 1]
# V2