LeetCode ยท #76

Minimum Window Substring Solution

Given strings s and t, return the minimum window in s that contains all characters of t.

01
Section One ยท Problem

Problem Statement

๐Ÿท๏ธ

Difficulty

Hard

๐Ÿ”—

LeetCode

Problem #76

๐Ÿ—๏ธ

Pattern

Sliding Window โ€” expand then shrink

Given two strings s and t of lengths m and n, 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 the empty string "".

Example
Input: s = "ADOBECODEBANC", t = "ABC" Output: "BANC" // "BANC" contains A, B, C. No shorter window does.
Example 2
Input: s = "a", t = "aa" Output: "" // Need two 'a's but s has only one โ†’ impossible
Constraints
โ€ข 1 โ‰ค s.length, t.length โ‰ค 10โต โ€ข s and t consist of uppercase and lowercase English letters
02
Section Two ยท Approach 1

Brute Force โ€” O(nยฒ ยท m)

Check every substring of s to see if it contains all characters of t. For each substring, build a frequency map and compare. Track the shortest valid one.

Problem: O(nยฒ) substrings, each costing O(m) to verify. A sliding window expands right to cover all characters, then shrinks left to minimize โ€” hitting each character at most twice for O(n + m) total.
Java โ€” Brute Force (TLE)
class Solution { public String minWindow(String s, String t) { String result = ""; for (int i = 0; i < s.length(); i++) { for (int j = i + t.length(); j <= s.length(); j++) { String sub = s.substring(i, j); if (containsAll(sub, t)) if (result.isEmpty() || sub.length() < result.length()) result = sub; } } return result; } // helper to check if sub contains all chars of t private boolean containsAll(String sub, String t) { int[] count = new int[128]; for (char c : sub.toCharArray()) count[c]++; for (char c : t.toCharArray()) if (--count[c] < 0) return false; return true; } }
Python โ€” Brute Force (TLE)
from collections import Counter class Solution: def minWindow(self, s: str, t: str) -> str: t_count = Counter(t) result = "" for i in range(len(s)): for j in range(i + len(t), len(s) + 1): if not (t_count - Counter(s[i:j])): if not result or j - i < len(result): result = s[i:j] return result
MetricValue
TimeO(nยฒ ยท m)
SpaceO(m)
03
Section Three ยท Approach 2

Sliding Window โ€” O(n + m)

Two phases that repeat: expand the right pointer until the window contains all characters of t, then shrink the left pointer to find the minimum valid window. Track when all required characters are satisfied using a formed counter.

๐Ÿ’ก Mental model: Imagine you're casting a fishing net (the window) in a river of characters. First, you widen the net rightward until you've caught all the required fish (characters of t). Then you tighten the left side to use the smallest possible net โ€” as soon as a required fish escapes, you stop tightening and expand right again. You record the smallest net size that ever held all targets.
Algorithm
  • Step 1: Build tCount โ€” frequency map of t. Let required = number of unique characters in t.
  • Step 2: Maintain windowCount for the current window and formed = how many unique chars in t are fully satisfied.
  • Step 3: Expand right: add s[right] to windowCount. If windowCount[c] == tCount[c], increment formed.
  • Step 4: While formed == required: record window if smaller than best, then shrink left โ€” decrement windowCount[s[left]], if it drops below tCount, decrement formed. left++.
๐ŸŽฏ Key insight โ€” formed counter:
  • Instead of comparing entire frequency maps each step (O(52)), we track how many of t's unique characters are fully satisfied.
  • When a character's window count reaches its required count, formed++.
  • When it drops below, formed--. Checking formed == required is O(1).
04
Section Four ยท Trace

Visual Walkthrough

Trace through s = "ADOBECODEBANC", t = "ABC":

Expand right to cover, shrink left to minimize
t = "ABC" โ†’ need: A=1, B=1, C=1 (required=3) s = A D O B E C O D E B A N C 0 1 2 3 4 5 6 7 8 9 10 11 12 Expand โ†’ r=5: window "ADOBEC" has A,B,C โ†’ formed=3 โœ“ Shrink โ† L=0โ†’1: remove A โ†’ formed=2. Window was [0,5]="ADOBEC" len=6 Expand โ†’ r=9: window "DOBECODB" + need A... r=10: got A "DOBECODEBA" has A,B,C โ†’ formed=3 โœ“ len=10 (worse) Shrink โ† L=1โ†’2โ†’3... until [3,10]="BECODEBA" len=8 then [5,10]="CODEBA" len=6, then [6,10]โ†’ lose C โ†’ formed=2 Expand โ†’ r=12: got C โ†’ "ODEBANC" โ†’ formed=3 โœ“ Shrink โ† [6,12]โ†’[9,12]="BANC" len=4 โ† smallest! shrink more โ†’ lose B โ†’ formed=2. Stop. Answer: "BANC" โœ“
05
Section Five ยท Implementation

Code โ€” Java & Python

Java โ€” Sliding Window
import java.util.HashMap; class Solution { public String minWindow(String s, String t) { if (t.length() > s.length()) return ""; HashMap<Character, Integer> tCount = new HashMap<>(); for (char c : t.toCharArray()) tCount.merge(c, 1, Integer::sum); int required = tCount.size(); int formed = 0; HashMap<Character, Integer> window = new HashMap<>(); int left = 0, minLen = Integer.MAX_VALUE, minStart = 0; for (int right = 0; right < s.length(); right++) { char c = s.charAt(right); window.merge(c, 1, Integer::sum); if (tCount.containsKey(c) && window.get(c).intValue() == tCount.get(c).intValue()) formed++; while (formed == required) { if (right - left + 1 < minLen) { minLen = right - left + 1; minStart = left; } char leftChar = s.charAt(left); window.put(leftChar, window.get(leftChar) - 1); if (tCount.containsKey(leftChar) && window.get(leftChar) < tCount.get(leftChar)) formed--; left++; } } return minLen == Integer.MAX_VALUE ? "" : s.substring(minStart, minStart + minLen); } }
Python โ€” Sliding Window
from collections import Counter class Solution: def minWindow(self, s: str, t: str) -> str: if len(t) > len(s): return "" t_count = Counter(t) required = len(t_count) formed = 0 window = {} left = 0 min_len = float('inf') min_start = 0 for right in range(len(s)): c = s[right] window[c] = window.get(c, 0) + 1 if c in t_count and window[c] == t_count[c]: formed += 1 while formed == required: if right - left + 1 < min_len: min_len = right - left + 1 min_start = left window[s[left]] -= 1 if s[left] in t_count and window[s[left]] < t_count[s[left]]: formed -= 1 left += 1 return "" if min_len == float('inf') else s[min_start:min_start + min_len]
06
Section Six ยท Analysis

Complexity Analysis

ApproachTimeSpaceTrade-off
Brute ForceO(nยฒ ยท m)O(m)Check all substrings
Sliding Window โ† optimal O(n + m) O(m) Each char enters/leaves window once. O(m) for t's freq map.
07
Section Seven ยท Edge Cases

Edge Cases & Pitfalls

CaseInputWhy It Matters
t longer than ss="a", t="aa"Impossible โ†’ return "".
Exact matchs="abc", t="abc"The entire string is the minimum window.
Duplicate chars in ts="aa", t="aa"Need two a's. Window count must meet the required count for each char.
Single chars="abcda", t="a"Minimum window is "a" at index 0 (or 4). Length 1.
No valid windows="abc", t="d"Character d doesn't exist in s โ†’ "".
Case sensitives="Aa", t="a"'A' โ‰  'a'. Only index 1 matches. Use int[128] for ASCII.
โš  Common Mistake: Using == to compare Integer objects in Java. window.get(c) == tCount.get(c) compares references, not values, for integers outside the cached range [-128, 127]. Use .intValue() or .equals() to compare correctly.

โ† Back to Sliding Window problems