“Longest substring without repeating characters.” “Maximum sum subarray of size k.” “Smallest window containing all characters of t.” These problems appear in FAANG interview loops constantly, and they share a shape: find the best contiguous chunk of an array or string.
The naive approach enumerates every subarray (O(n²) of them) and evaluates each one, often for O(n³) total. The sliding window technique solves the same problems in O(n) with one idea: when the window moves, don’t recompute its contents from scratch: update them incrementally. A window sliding one step right adds one element and (maybe) drops one element. Everything else it contains is unchanged, so recomputing it is pure waste.
In this post we’ll build the technique from zero: fixed windows first, then the variable-size grow/shrink template, then five interview problems in Python, from warm-up to genuinely hard.
What Is a Sliding Window?
A sliding window is a contiguous range [left, right] over an array or string, plus some window state (a running sum, a character-count hash map, a count of distinct elements) that describes what’s currently inside.
Two pointers define the window’s edges, which is why this technique is often lumped in with the two pointer technique. The distinction worth keeping sharp: classic two pointers cares about the endpoints (a pair that sums to a target); sliding window cares about everything between them, summarized in the state. If the problem says “pair,” think two pointers. If it says “substring” or “subarray,” think window.
Both pointers only ever move right. right moves at most n times, left moves at most n times, so the total work is O(n), even though the code contains a nested loop. That amortized argument is worth saying out loud in an interview; it’s the kind of complexity reasoning covered back in Day 3: Introduction to Time Complexity.
Fixed vs. Variable Windows
Every sliding window problem is one of two kinds, and identifying which one you’re facing is half the solution.
Fixed-size window. The problem hands you the window size: “subarray of size k,” “any window of 30 days.” The window slides one step at a time: add the entering element, remove the leaving element, update the answer. There’s nothing to decide: the bookkeeping is the whole problem.
Variable-size window. The problem asks for the longest or shortest window satisfying a condition: “longest substring with no repeats,” “smallest subarray with sum ≥ target.” Now the window breathes: it grows until the condition breaks (or is met), then shrinks from the left. All variable-window problems fit one template:
1def variable_window(sequence):
2 state = ... # counts, sum, whatever describes the window
3 left = 0
4 best = 0
5 for right in range(len(sequence)):
6 # 1. Grow: bring sequence[right] into the state
7 add(state, sequence[right])
8
9 # 2. Shrink: while the window is invalid, evict from the left
10 while invalid(state):
11 remove(state, sequence[left])
12 left += 1
13
14 # 3. Record: window [left, right] is now valid
15 best = max(best, right - left + 1)
16 return best
Grow, shrink, record. The three problems at the end of this post are all instances of this template with different state and invalid definitions, and that’s precisely why the technique is learnable: you memorize one skeleton, not twenty solutions.
The window state is usually a hash map of counts, so if defaultdict and Counter aren’t second nature yet, skim Day 23: Hash Tables and Hash Maps and Sets: The Most Underrated FAANG Topic first.
Now, the five problems.
Problem 1: Maximum Sum Subarray of Size K (Easy, fixed window)
Given an array of integers and an integer k, find the maximum sum of any contiguous subarray of size k.
The brute force computes each of the n−k+1 window sums independently: O(n·k). The window version notices that adjacent windows differ by exactly two elements:
1def max_sum_subarray(nums, k):
2 window_sum = sum(nums[:k])
3 best = window_sum
4 for right in range(k, len(nums)):
5 window_sum += nums[right] - nums[right - k] # add entering, drop leaving
6 best = max(best, window_sum)
7 return best
O(n) time, O(1) space. This problem is the technique in miniature: the entire trick is + entering − leaving. Everything that follows just replaces the running sum with richer state.
Problem 2: Longest Substring Without Repeating Characters (Medium)
Find the length of the longest substring with no repeated characters.
The canonical variable-window problem. State: a set (or count map) of characters in the window. Invalid: the entering character is already present.
1def longest_unique_substring(s):
2 seen = set()
3 left = 0
4 best = 0
5 for right in range(len(s)):
6 while s[right] in seen: # shrink until the duplicate is gone
7 seen.remove(s[left])
8 left += 1
9 seen.add(s[right])
10 best = max(best, right - left + 1)
11 return best
Trace it on "abcabcbb": the window stretches to abc, hits the second a, evicts from the left until the first a is gone, and keeps rolling. Every character enters the set once and leaves at most once. That’s the amortized O(n).
The follow-up interviewers love: instead of evicting one at a time, store each character’s last index in a dictionary and jump left directly past the previous occurrence. Same complexity, fewer operations. Offer it when asked to optimize.
Problem 3: Minimum Size Subarray Sum (Medium, shrink-to-optimize)
Given an array of positive integers and a target, find the minimal length of a contiguous subarray whose sum is ≥ target.
A subtle inversion of the template. Here a bigger window is always valid-or-better, so we shrink while the condition holds, recording answers as we squeeze:
1def min_subarray_len(target, nums):
2 left = 0
3 window_sum = 0
4 best = float("inf")
5 for right in range(len(nums)):
6 window_sum += nums[right]
7 while window_sum >= target: # valid: try to shrink
8 best = min(best, right - left + 1)
9 window_sum -= nums[left]
10 left += 1
11 return best if best != float("inf") else 0
Notice the pattern flip: for longest window problems, shrink while invalid and record after the loop; for shortest window problems, shrink while valid and record inside the loop. Mixing these up is the single most common sliding window bug.
One honest caveat to mention in an interview: this works because all numbers are positive, so growing can only increase the sum and shrinking can only decrease it. The window behaves monotonically. With negative numbers the window logic breaks, and you’d reach for prefix sums instead.
Problem 4: Longest Repeating Character Replacement (Medium–Hard)
Given a string and an integer k, you may replace at most k characters. Find the length of the longest substring of a single repeated character you can create.
The insight that unlocks it: a window is fixable if window_length - count_of_most_frequent_char <= k. That difference is exactly how many replacements you’d need.
1from collections import defaultdict
2
3def character_replacement(s, k):
4 counts = defaultdict(int)
5 left = 0
6 max_freq = 0
7 best = 0
8 for right in range(len(s)):
9 counts[s[right]] += 1
10 max_freq = max(max_freq, counts[s[right]])
11 if (right - left + 1) - max_freq > k: # too many replacements needed
12 counts[s[left]] -= 1
13 left += 1
14 best = max(best, right - left + 1)
15 return best
Two details make this problem a favorite filter question. First, max_freq is never decremented when the window shrinks. A “stale” max only makes the window conservatively keep its size, and since we only care about the maximum length ever achieved, that’s harmless. Second, the shrink step is an if, not a while: the window never needs to shrink by more than one, because it only ever grew by one. Both are safe, neither is obvious, and explaining why they’re safe is exactly the depth interviewers are probing for.
Problem 5: Minimum Window Substring (Hard)
Given strings s and t, return the minimum window in s that contains every character of t (with multiplicity).
The final boss of sliding window. State: how many characters of t the window still needs. Grow until the window covers t, then shrink while it still does:
1from collections import Counter
2
3def min_window(s, t):
4 if not t or not s:
5 return ""
6 need = Counter(t)
7 missing = len(t) # chars still needed (with multiplicity)
8 left = 0
9 best = (float("inf"), 0, 0) # (length, start, end)
10
11 for right, char in enumerate(s):
12 if need[char] > 0:
13 missing -= 1
14 need[char] -= 1
15
16 while missing == 0: # window covers t: shrink to optimize
17 if right - left + 1 < best[0]:
18 best = (right - left + 1, left, right)
19 need[s[left]] += 1
20 if need[s[left]] > 0: # evicted a required char
21 missing += 1
22 left += 1
23
24 return "" if best[0] == float("inf") else s[best[1]:best[2] + 1]
The clever bookkeeping: need goes negative for surplus characters, and missing only ticks back up when we evict a character the window truly needed. That keeps the validity check O(1) instead of re-scanning the count map. O(|s| + |t|) overall.
If you solve Problems 2–5 back to back, you’ll notice you wrote the same loop four times with different state. That’s the win condition: the template has become an instinct.
How to Recognize a Sliding Window Problem
The checklist to run in a live interview:
- The answer is a contiguous subarray or substring. (Non-contiguous, meaning “subsequence”, usually points to dynamic programming; start at Day 30: Dynamic Programming Introduction.)
- The problem says longest / shortest / maximum / minimum / at most k / exactly k about that chunk.
- Window validity is monotonic-ish: growing moves you toward (or away from) validity in a predictable direction, so shrinking is meaningful.
- A fixed chunk size is given → fixed window; an optimal size is asked for → variable window.
And the two follow-up answers to have ready: the nested loop is still O(n) because each pointer moves at most n times total, and the space cost is the window state: O(1) for sums, O(min(n, alphabet)) for count maps.
Where to Go Next
Sliding window is one of the highest-frequency patterns in real interview loops, and it’s learnable in a week because it’s one template, not twenty tricks. In the 60 Days of Algorithms challenge, the prerequisites are sequenced deliberately (arrays in Day 4, hash tables in Day 23), so the state bookkeeping never blocks you. Create a free account to work through the full curriculum one day at a time.
When you’re done here, the natural next pattern is the sibling technique for pairs and in-place problems: Two Pointer Technique: When to Use It and 6 Problems Solved.
Related Articles
- Two Pointer Technique: When to Use It and 6 Problems Solved
- Hash Maps and Sets: The Most Underrated FAANG Topic
- Day 23: Hash Tables
- Strings and String Manipulation
- The Best FAANG Interview Prep Resources in 2026 (Free + Paid)
Happy coding, and keep the window sliding.