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
rightpointer -> increasehave, Oncehave == need-> moveleftpointer 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_mapand using this we will keep track of the theleftandrightpointers 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&rightpointer, then keep moving the right pointer from initial0position 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 incrementhaveby 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==havecondition 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 pointertoB, thehavevalue will be2(right side)Then once
rreaches toC, thehave==needwill beTrue. (both will be3). Now calculatemin_len(5-0 = 5). Then incrementleft pointerone step which will reduce thehavecount and that will break the while loop.Now once
rmoves toAthehave=needwill again beTrue. Thewhileloop will keep running andlwill be incremented till it reaches toC. Themin_lenwill again be10-5 = 5.lwill be incremented once more and after that the while loop will break.Finally,
rwill move toCand againhave=needwill again beTrue. We will keep increasingland calculatemin_lenfor every iteration. Finally, thewhileloop will break for the last time afterlcrossesB. Thats themin_lenof12-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.





