By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
(A Complete FAANG-Level Interview Guide)
"This problem appears in 1 out of every 3 onsite interviews—master it, and you prove you can handle sliding windows, hash maps, and edge-case optimization at a senior-engineer level."
Before tackling Minimum Window Substring, ensure you understand: 1. Hash Maps (Dictionaries) – For tracking character frequencies in O(1) time. 2. Sliding Window Technique – Expanding and contracting a window to find valid substrings efficiently. 3. Two-Pointer Technique – Using left and right pointers to traverse the string in O(n) time.
left
right
t
"ADOBECODEBANC"
t = "ABC"
"BANC"
{'A':1, 'B':1, 'C':1}
right++
left++
formed == required
right - left + 1 >= min_len
(Repeat this checklist for every Minimum Window Substring problem.)
s
len(t) > len(s)
""
If t has duplicate characters, account for their counts.
Initialize Frequency Map for t
target_counts
required = len(target_counts) (number of unique characters to match).
required = len(target_counts)
Sliding Window Setup
left = 0
right = 0
window_counts = {}
formed = 0
min_len = ∞, result = "" (track the smallest valid window).
min_len = ∞
result = ""
Expand the Window (Move right)
s[right]
window_counts
If s[right] is in target_counts and window_counts[s[right]] == target_counts[s[right]], increment formed.
window_counts[s[right]] == target_counts[s[right]]
formed
Contract the Window (Move left)
While formed == required (window is valid):
min_len
result
s[left]
target_counts[s[left]]
Terminate & Return
∞
Problem: Given strings s = "ADOBECODEBANC" and t = "ABC", return the minimum window in s that contains all characters of t.
s = "ADOBECODEBANC"
Step-by-Step Walkthrough: 1. Edge Cases: - s and t are non-empty, len(t) <= len(s) → proceed.
len(t) <= len(s)
Frequency Map for t: python target_counts = {'A': 1, 'B': 1, 'C': 1} required = 3
python target_counts = {'A': 1, 'B': 1, 'C': 1} required = 3
Sliding Window Setup: python left = right = 0 window_counts = {} formed = 0 min_len = float('inf') result = ""
python left = right = 0 window_counts = {} formed = 0 min_len = float('inf') result = ""
Expand right:
'A'
window_counts = {'A':1}
formed = 1
right = 1
'D'
right = 2
'O'
right = 3
'B'
window_counts = {'A':1, 'B':1}
formed = 2
right = 4
'E'
right = 5 → 'C' → window_counts = {'A':1, 'B':1, 'C':1} → formed = 3 (valid window).
right = 5
'C'
window_counts = {'A':1, 'B':1, 'C':1}
formed = 3
Contract left:
"ADOBEC"
0-5
min_len = 6
result = "ADOBEC"
window_counts['A'] = 0
left = 1
left = 2
left = 3
window_counts['B'] = 0
left = 4
left = 5 → 'C' → window_counts['C'] = 0 → formed = 0 (invalid).
left = 5
window_counts['C'] = 0
Continue Expanding:
right = 6
right = 7
right = 8
right = 9
window_counts = {'B':1}
right = 10
window_counts = {'B':1, 'A':1}
right = 11
'N'
right = 12 → 'C' → window_counts = {'B':1, 'A':1, 'C':1} → formed = 3 (valid window).
right = 12
window_counts = {'B':1, 'A':1, 'C':1}
Contract left Again:
"CODEBA"
6-12
left = 6
left = 7
left = 8
left = 9
left = 10
left = 11
left = 12 → 'C' → window_counts['C'] = 0 → formed = 0 (invalid).
left = 12
Final Window:
9-12
4
Final Code:
from collections import defaultdict def minWindow(s: str, t: str) -> str: if not s or not t or len(t) > len(s): return "" target_counts = defaultdict(int) for char in t: target_counts[char] += 1 required = len(target_counts) left = right = 0 window_counts = defaultdict(int) formed = 0 min_len = float('inf') result = "" while right < len(s): char = s[right] window_counts[char] += 1 if char in target_counts and window_counts[char] == target_counts[char]: formed += 1 while left <= right and formed == required: current_window_len = right - left + 1 if current_window_len < min_len: min_len = current_window_len result = s[left:right+1] left_char = s[left] window_counts[left_char] -= 1 if left_char in target_counts and window_counts[left_char] < target_counts[left_char]: formed -= 1 left += 1 right += 1 return result
Time Complexity: O(|s| + |t|) (each character is processed at most twice). Space Complexity: O(|s| + |t|) (for the hash maps).
Why This Works: - The sliding window ensures we only traverse s once while dynamically adjusting the window to find the smallest valid substring. - The formed counter guarantees we only consider windows that contain all characters of t.
Problem: s = "AAABBBCA", t = "ABCA" → Return "ABBBCA" (smallest window with at least 1 'A', 1 'B', 1 'C', and 1 'A').
s = "AAABBBCA"
t = "ABCA"
"ABBBCA"
Key Twist: - t has duplicate 'A' → target_counts = {'A':2, 'B':1, 'C':1}.
target_counts = {'A':2, 'B':1, 'C':1}
Solution: - The same framework applies, but formed only increments when window_counts[char] == target_counts[char] (not just >=).
window_counts[char] == target_counts[char]
>=
Final Code: (Same as above, but target_counts now has 'A':2.)
'A':2
Why This Works: - The formed counter ensures we don’t count a character as "satisfied" until its count in the window matches its count in t.
Problem: Given s = "aabdec", find the smallest substring containing all distinct characters of s (i.e., 'a', 'b', 'd', 'e', 'c').
s = "aabdec"
'a', 'b', 'd', 'e', 'c'
Key Twist: - t is not given; instead, we must find all distinct characters in s first.
Solution: 1. Compute target_counts as the frequency of all distinct characters in s. 2. Apply the same sliding window framework.
from collections import defaultdict def minWindowAllDistinct(s: str) -> str: if not s: return "" target_counts = defaultdict(int) for char in s: target_counts[char] += 1 required = len(target_counts) left = right = 0 window_counts = defaultdict(int) formed = 0 min_len = float('inf') result = "" while right < len(s): char = s[right] window_counts[char] += 1 if window_counts[char] == target_counts[char]: formed += 1 while left <= right and formed == required: current_window_len = right - left + 1 if current_window_len < min_len: min_len = current_window_len result = s[left:right+1] left_char = s[left] window_counts[left_char] -= 1 if window_counts[left_char] < target_counts[left_char]: formed -= 1 left += 1 right += 1 return result
Time Complexity: O(|s|) (each character is processed twice). Space Complexity: O(|s|) (for the hash maps).
Why This Works: - The problem reduces to the same sliding window pattern, but we first compute target_counts from s itself.
current_window_len < min_len
s[left:right]
s[left:right+1]
[inclusive:exclusive]
window_counts[char]
window_counts[char] < target_counts[char]
"Alright, let’s lock this in. Minimum Window Substring is all about sliding windows and hash maps. Here’s the playbook:
required
Remember: The key is formed vs. required. Only contract left when the window is valid, and only decrement formed when a character’s count drops below its target. Practice this 3 times, and you’ll crush it in the interview. Good luck!
You’ve got this! ?
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.