Minimum Window Substring — Coding Interview Walkthrough
You’re in a coding interview. The interviewer gives you s = "ADOBECODEBANC" and t = "ABC" and asks for the minimum window in s that contains all characters of t. You write a sliding window, find a valid window, and return it. The interviewer changes the input to t = "AAB" and your solution returns a window with only one A. You used a set instead of a frequency map, and now there’s a correctness bug you need to fix with the clock running.
This walkthrough covers the full solution: the two-phase sliding window, the formed counter that keeps validity checks O(1), and the frequency map design that handles duplicate characters correctly.
The Problem
Given two strings s and t, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If no such window exists, return "".
Example 1
Input
s = "ADOBECODEBANC", t = "ABC"
Output
"BANC"
Example 2
Input
s = "a", t = "a"
Output
"a"
Example 3
Input
s = "a", t = "b"
Output
""
In Example 1, the shortest window containing A, B, and C is "BANC" (length 4). The key challenge: t can contain duplicate characters. t = "AA" requires the window to contain at least two As.
Already comfortable with the solution? Practice it in a mock interview →
What Interviewers Are Actually Testing
| Skill | What Interviewers Observe |
|---|---|
| Sliding window pattern | Do you know when to expand vs. shrink? |
| Frequency map design | Do you use two maps (need vs. window) and a formed counter? |
| Duplicate character handling | Does your solution require multiple occurrences when t has duplicates? |
| Window validity tracking | Do you use a formed counter rather than re-scanning? |
| Optimization instinct | Do you shrink greedily to find the minimum? |
Step 1: Clarifying Questions
1. Can t contain duplicate characters?
Yes, this is the critical clarification. If t = "AA", the window needs at least two As. Using a set instead of a counter for t produces wrong answers.
2. Is the answer guaranteed to exist?
No. Return "" if no valid window exists.
3. Are characters case-sensitive?
Yes. "A" and "a" are distinct.
4. Does the window need to be contiguous?
Yes, a contiguous slice of s.
Step 2: A First (Non-Optimal) Idea
Check every possible substring:
from collections import Counter
def min_window_brute(s: str, t: str) -> str:
need = Counter(t)
best = ""
for left in range(len(s)):
for right in range(left + 1, len(s) + 1):
window_count = Counter(s[left:right])
if all(window_count[c] >= need[c] for c in need):
if not best or len(s[left:right]) < len(best):
best = s[left:right]
return best
O(n^2 x m) with n^2 substrings and O(m) validity checks. Far too slow for n = 100,000.
Step 3: The Key Insight
Use a two-phase sliding window. Expand the right pointer until the window is valid (contains all required characters at required frequencies). Then shrink the left pointer as far as possible while the window stays valid, recording the minimum. The
formedcounter tracks how many distinct characters intare currently satisfied, making validity checks O(1).
When adding a character: if its window count now equals its required count, increment formed. When removing: if its count drops below required, decrement formed. The window is valid when formed == required.
---
Step 4: Optimal Strategy
- Build
needfromt. Letrequired = len(need). - Initialize
window_counts = {},formed = 0,left = 0. - Track
best = (infinity, 0, 0). - Expand with
right:- Add
s[right]to window_counts. - If character is in
needand count matches, incrementformed. - While
formed == required, try shrinking:- Update best if current window is smaller.
- Remove
s[left], check ifformedshould decrement. - Advance
left.
- Add
- Return the best window or
"".
Python Implementation
from collections import Counter
def min_window(s: str, t: str) -> str:
if not s or not t:
return ""
need = Counter(t)
required = len(need)
window_counts = {}
formed = 0
left = 0
best = float("inf"), 0, 0
for right in range(len(s)):
char = s[right]
window_counts[char] = window_counts.get(char, 0) + 1
if char in need and window_counts[char] == need[char]:
formed += 1
while formed == required and left <= right:
if right - left + 1 < best[0]:
best = (right - left + 1, left, right)
left_char = s[left]
window_counts[left_char] -= 1
if left_char in need and window_counts[left_char] < need[left_char]:
formed -= 1
left += 1
return "" if best[0] == float("inf") else s[best[1]: best[2] + 1]
For s = "ADOBECODEBANC", t = "ABC":
- Expand right to index 5 (
C): window ="ADOBEC", formed = 3 - Shrink: remove
A, formed = 2. Best so far ="ADOBEC"(len 6) - Expand to index 10 (
A): formed = 3 again - Shrink through D, O, B: formed drops when removing B. Best =
"CODEBA"(len 6) - Expand to index 12 (
C): formed = 3 - Shrink through E, C, O, D, E: window =
"BANC"(len 4). Best updated.
Result: "BANC" ✓
Time & Space Complexity
| Aspect | Complexity | Explanation |
|---|---|---|
| Time | O(n + m) | Each character added and removed at most once; building need costs O(m) |
| Space | O(m + k) | need stores m characters; window_counts stores at most k unique chars |
Common Interview Mistakes
-
Not tracking
formed, re-checking validity from scratch. Re-computingall(window_counts[c] >= need[c] for c in need)each step makes it O(n x m). -
Using a set instead of a counter for
t. Fails on duplicates.t = "AA"requires twoAs. -
Decrementing
formedtoo eagerly. Only decrement when count drops below required, not on every decrease. -
Incrementing
formedfor characters not inneed. Track only characters int. -
Off-by-one in the return slice.
s[left:right + 1]because Python slicing is exclusive on the right. -
Using
ifinstead ofwhilefor the shrink phase. The window must shrink as far as possible.
What a Strong Candidate Sounds Like
“I’ll use a two-phase sliding window. Expand right until the window is valid, then shrink from left as far as possible while valid, recording the minimum. To check validity in O(1), I maintain a
formedcounter: it increments when a character’s window count hits its required amount, decrements when it drops below. The window is valid whenformedequals the number of distinct characters int. Every character is added and removed at most once, giving O(n + m) total.”
Example Interview Dialogue
Interviewer: What happens when t has duplicate characters?
Candidate: The need map captures frequencies: t = "AAB" gives need = {'A': 2, 'B': 1}. formed only increments for 'A' when window_counts['A'] reaches exactly 2. Adding a third A doesn’t change formed. When shrinking, formed decrements only when window_counts['A'] drops below 2.
Interviewer: Could you solve this without the formed counter?
Candidate: You could check all(window_counts.get(c, 0) >= need[c] for c in need) each step, but that’s O(m) per step, making the solution O(n x m). The formed counter reduces that to O(1).
Related Problems to Practice
These problems build on the same sliding window and frequency tracking patterns:
- Longest Substring Without Repeating Characters (LeetCode #3). Simpler sliding window. Good warm-up.
- Permutation in String (LeetCode #567). Fixed-size window with frequency map. Direct stepping stone.
- Find All Anagrams in a String (LeetCode #438). Same fixed-size window idea, returns all positions.
- Substring with Concatenation of All Words (LeetCode #30). Extends to word-level matching.
- Sliding Window Maximum (LeetCode #239). Different constraint (monotonic deque) but same window mechanics.
Practice This in a Mock Interview
This is a problem where the complexity is in the interactions between moving parts: the two-phase window, the formed counter, the frequency map. Candidates who understand each piece individually still mix up when to increment vs. decrement formed, or forget while vs. if in the shrink phase.
The only way to make those interactions feel automatic is to implement this from scratch, out loud, under time pressure.
Start a mock interview for Minimum Window Substring on Intervu.
Further reading:
- How to Prepare for a Coding Interview in 2026, the complete roadmap and study plans
- Why LeetCode alone isn’t enough, and what to practice instead
- Practice any LeetCode problem as a live mock interview
- The Grind 75 Pathway, a structured study plan with AI practice links
- Browse all walkthroughs on GitHub, condensed solutions with code