Sliding Window - Minimum Window Substring
All diagrams presented herein are original creations, meticulously designed to enhance comprehension and recall. Crafting these aids required considerable effort, and I kindly request attribution if this content is reused elsewhere.
Difficulty : Medium
Two Pointers, Two Maps, Move
right
pointer -> increasehave
, Oncehave == need
-> moveleft
pointer in loop untilhave < need
Problem
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 ""
.
Example 1:
1
2
3
Input: s = "ADOBECODEBANC", t = "ABC"
Output: "BANC"
Explanation: The minimum window substring "BANC" includes 'A', 'B', and 'C' from string t.
Example 2:
1
2
3
Input: s = "a", t = "a"
Output: "a"
Explanation: The entire string s is the minimum window.
Example 3:
1
2
3
4
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.
Solution
Once you know the solution writing code is very simple. Here we will use two maps
window_map
&t_map
and using this we will keep track of the theleft
andright
pointers of the window. We will also use two additonal parametershave
&need
.Lets first create map of all the letters we need including their occurances as duplicates are allowed.
1 2 3 4 5
# Our input is s = 'ADOBECODEBANC' and t= 'ABC' t_map = {} for c in t: t_map[c]=1+t_map.get(c,0) print(t_map)
1
{'A': 1, 'B': 1, 'C': 1}
Next, we will define two parameters to track if we have all the letters in our window including their occurrences.
1
have, need = 0, len(t_map)
The idea is to create a
left
&right
pointer, then keep moving the right pointer from initial0
position and keep adding the corresponding letter to another map namedwindow_map
.1 2 3 4 5
l = 0 window_map = {} for r in range(len(s)): c = s[r] window_map[c] = 1+window_map.get(c, 0)
Everytime after letter is added to
window_map
, find out if for that letter the requiremts are met using thet_map
. If yes, then incrementhave
by one.1 2
if c in t_map and t_map[c]==window_map[c]: have=have+1
Now whenever
need==have
, find the length of the window. If the length We need a while loop here as duplicate might be there.1 2 3 4
while need == have: if (r+1)-l < min_len : min_len=(r+1)-l result=[l,r]
Once we have the current result, now its time to keep shrinking the window from left until the
need==have
condition breaks. Remove one item fromwindow_map
, find if we need to reducehave
.
Notice : Here we are using
s[l]
and nots[r]
(which isc
).
1
2
3
4
5
window[s[l]]-=1
if s[l] in t_map and window[s[l]] < t_map[s[l]]:
have-=1
l+=1
Let’s visualize this step by step now. After moving
right pointer
toB
, thehave
value will be2
(right side)Then once
r
reaches toC
, thehave==need
will beTrue
. (both will be3
). Now calculatemin_len
(5-0 = 5
). Then incrementleft pointer
one step which will reduce thehave
count and that will break the while loop.Now once
r
moves toA
thehave=need
will again beTrue
. Thewhile
loop will keep running andl
will be incremented till it reaches toC
. Themin_len
will again be10-5 = 5
.l
will be incremented once more and after that the while loop will break.Finally,
r
will move toC
and againhave=need
will again beTrue
. We will keep increasingl
and calculatemin_len
for every iteration. Finally, thewhile
loop will break for the last time afterl
crossesB
. Thats themin_len
of12-9 = 3
.
Visualize the code
Code
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
def min_window_sub_string(s, t):
window_map, t_map = {}, {}
for c in t:
t_map[c] = 1+t_map.get(c, 0)
l = 0
result = [0, 0]
min_len = float('inf')
have, need = 0, len(t_map)
for r in range(len(s)):
c = s[r]
window_map[c] = 1+window_map.get(c, 0)
if c in t_map and t_map[c] == window_map[c]:
have += 1
while have == need:
if min_len > (r+1) - l:
min_len = (r+1) - l
result = [l, r]
# pop leftmost element from window
window_map[s[l]] = window_map[s[l]]-1
# Verify if window still has all char needed
if s[l] in t_map and window_map[s[l]] < t_map[s[l]]:
have -= 1
l = l+1
l, r = result
return s[l:r+1] if min_len != float("inf") else ""
print(min_window_sub_string('ADOBECODEBANC', 'ABC'))
1
BANC
Runtime Complexity
The runtime will be O(n)
as we are simply scanning through the array once.