Sliding Window Coding Interview: A Reasoning Guide
Learn to recognise sliding window questions, justify every pointer move out loud, and explain the amortised O(n) argument honestly in a coding interview.
The sliding window pattern is a way of scanning a contiguous run of elements once, growing and shrinking that run instead of recomputing it from scratch. In a sliding window coding interview, the pattern itself is rarely the hard part. The hard part is explaining why the window may shrink without skipping a valid answer, and saying the complexity out loud without hedging.
This guide treats sliding window as a reasoning skill. You will see how to recognise the pattern, how to narrate the invariant while you code, and how to answer the follow-up question that trips people up: "Why is this linear when there is a loop inside a loop?"
What the Sliding Window Pattern Actually Is
A window is a contiguous range of a sequence — a subarray or a substring — that you maintain as you move through the input. Instead of asking "what is the best range starting here?" for every starting point, you keep one range and adjust its edges.
The saving is easiest to see against brute force. Suppose you want the maximum sum of any k consecutive numbers in an array of length n. The brute-force version computes each group of k from scratch, which is about k·n additions. The window version adds the incoming element and subtracts the outgoing one, which is about 2n operations. Same answer, far less repeated work, and the gap widens as k grows.
There are two common shapes:
- Fixed-size windows. The window always holds exactly k elements. You slide it one step at a time.
- Variable-size windows. The window grows while a validity condition holds and shrinks when it breaks. "Longest substring without repeating characters" is the standard example.
One honest caveat: this pattern applies to contiguous ranges. If a question asks for any subset, any pair, or elements in any order, sliding window is the wrong tool. Recognising that early saves you from forcing a pattern that cannot work.
How to Recognise a Sliding Window Coding Interview Question
The wording usually gives it away. Look for "contiguous", "substring", "subarray", "window of size k", "longest", "shortest", and "at most k". Any of these combined with a sequence is a strong signal.
The constraints give a second signal. If the input can be large and the brute-force answer would check every pair of positions, the intended solution is probably linear or near-linear. An O(n²) scan over a large input is usually the hint that a window is expected.
Run this checklist in the first minute of a question:
- Is the answer a contiguous range of the input, or does order not matter?
- Is there a property of the window I can check incrementally — a sum, a count, a set of characters?
- When the window becomes invalid, can I fix it by moving the left edge forward?
- Does the problem ask for the longest, shortest, or best window by some measure?
If the answer to the first question is no, stop. Reach for prefix sums when you need sums of arbitrary ranges, or two pointers on a sorted array when the input can be ordered and you are matching pairs. These are different patterns with different correctness arguments, and mixing them up mid-interview is expensive.
Fixed-Size Windows: A Worked Example
A common fixed-size sliding window coding interview question is the maximum sum of any k consecutive elements. With k equal to 3 and the array [2, 1, 5, 1, 3, 2], the best window is [5, 1, 3] with sum 9.
The naive approach recomputes each triple: 2+1+5, then 1+5+1, then 5+1+3, and so on. The window approach computes the first triple once, then updates:
window_sum = sum(nums[0:k])
best = window_sum
for right in range(k, len(nums)):
window_sum += nums[right]
window_sum -= nums[right - k]
best = max(best, window_sum)Trace it on [2, 1, 5, 1, 3, 2] with k = 3, saying the invariant at each step: the window holds exactly k elements, ending at index right - 1.
- Start: window [2, 1, 5], sum 8, best 8.
- right = 3 (value 1): add 1, remove index 0 (value 2). Window [1, 5, 1], sum 7, best 8.
- right = 4 (value 3): add 3, remove index 1 (value 1). Window [5, 1, 3], sum 9, best 9.
- right = 5 (value 2): add 2, remove index 2 (value 5). Window [1, 3, 2], sum 6, best 9.
Answer 9. At every step the window still holds exactly three elements; only the edges moved.
For a sum, the order of the two updates does not matter, because addition is commutative. Do not generalise that to every update. If your window tracks something non-commutative — a running product with division, a string you build by appending, an ordered structure — the order matters, and the safe habit is to remove the outgoing element first, then add the incoming one.
What breaks in either order is being careless about which index leaves. The element leaving when right enters is at right - k, not right - k + 1. Off-by-one errors here are the most common way a correct idea produces a wrong answer.
The invariant to state before you write anything: at the top of every iteration, the window contains exactly k elements, ending at index right - 1. If you can say that sentence, the code almost writes itself, and the interviewer can follow your index arithmetic without guessing.
Variable-Size Windows: Growing and Shrinking
Now the classic variable-size sliding window coding interview question: the longest substring without repeating characters. In "abcabcbb" the answer is "abc", length 3.
You have two reasonable choices for the validity structure. A last-seen index map stores the most recent position of each character, which lets you jump the left pointer directly. A frequency map plus a shrink loop counts occurrences and moves left forward one step at a time until the window is valid again. The last-seen version is shorter for this problem; the frequency-map version generalises better, because it works when validity depends on counts rather than on a single duplicate.
Here is the frequency-map version, which is the one the shrink-loop argument below belongs to:
count = {}
left = 0
best = 0
for right, ch in enumerate(s):
count[ch] = count.get(ch, 0) + 1
while count[ch] > 1:
count[s[left]] -= 1
if count[s[left]] == 0:
del count[s[left]]
left += 1
best = max(best, right - left + 1)Trace it on "abcabcbb", narrating the invariant: the window [left, right] is valid — no repeated character — and it is the longest valid window ending at right.
- right = 0 ('a'): window "a", valid, best 1.
- right = 1 ('b'): window "ab", valid, best 2.
- right = 2 ('c'): window "abc", valid, best 3.
- right = 3 ('a'): adding 'a' makes count['a'] = 2, so the window is invalid. Shrink: remove 'a' at left 0, left becomes 1. Window "bca", valid, best stays 3.
- right = 4 ('b'): count['b'] = 2, so the window breaks again. Remove 'b' at left 1, left becomes 2. Window "cab", valid, best 3.
- right = 5 ('c'): count['c'] = 2, invalid once more. Remove 'c' at left 2, left becomes 3. Window "abc", valid, best 3.
- right = 6 ('b'): count['b'] = 2, so shrink again. Remove 'b' at left 3, left becomes 4. Window "cb", valid, best 3.
- right = 7 ('b'): count['b'] = 2, one more shrink. Remove 'b' at left 4, left becomes 5. Window "b", valid, best 3.
Answer 3. The shrink loop is where the correctness argument lives:
while not valid(window):
remove(s[left])
left += 1Every element enters the window once, when right passes it, and leaves at most once, when left passes it. That is the whole reason the nested loop is still linear. Say that sentence out loud — it is the answer to the follow-up question before it is asked.
Once you have this skeleton, the "at most k distinct characters" variant is a small edit. Keep a count of distinct characters in the window. While that count exceeds k, shrink from the left, decrementing the count of the outgoing character and dropping it when it reaches zero. Same shape, different validity check. If you can re-derive one from the other, you do not need to memorise both.
Reasoning Out Loud While You Code
Before typing, state the invariant. For the variable window: at the top of each iteration, the window [left, right] is valid, and it is the longest valid window ending at right. That single sentence carries the correctness argument, the update rule, and the complexity.
Then explain why left never moves backwards. Each time the window becomes invalid, the smallest fix is to advance the left edge past the offending element. Any earlier left position would still contain that element, so no valid window is skipped. That is the core of the proof, and it is worth saying in plain words rather than gesturing at the code.
Interviewers interrupt. When that happens, do not restart your explanation from the beginning. Restate the invariant in one sentence, then answer the specific question. If you are asked "what happens if the input is empty?", answer that question, then return to where you were.
When you feel stuck, trace a small concrete input by hand for two or three iterations, as in the traces above. Write the window contents in the margin. Watching left and right move on real values usually reveals the bug faster than staring at the loop. This habit is also what makes your reasoning visible, which is what is being assessed. Our blog collects companion guides on related topics, including sorting and Python.
Stating Time and Space Complexity With Confidence
The one-sentence version: each element is added to the window once and removed at most once, so the total work is linear in the length of the input. That is the amortised argument, and it is why a loop inside a loop is still O(n).
Be precise about what is inside the loop. The window movement is O(n). The cost of the operations on your validity structure is separate. A hash map gives expected O(1) insert and delete, so the whole solution is expected O(n). If you used a sorted structure instead, you would need to account for its cost honestly rather than claiming O(n) by habit.
Space complexity deserves the same care. Do not just say O(n) reflexively. If your structure is keyed by character, the space is bounded by the size of the alphabet, which is a constant for a fixed character set. If it is keyed by arbitrary integers, the bound is the number of distinct values currently in the window, which is at most the window size. Saying "O(1) for a fixed alphabet" or "bounded by the number of distinct values in the window" shows you know what you are counting.
Practise two versions: the one-sentence summary, and the follow-up justification if the interviewer pushes. Rehearse both until the first is automatic and the second is ready.
Common Mistakes and How to Catch Them
- Shrinking with
ifinstead ofwhile. If the window can become invalid by more than one element at a time, a singleifsilently breaks the invariant. Ask yourself: can one new element invalidate the window in more than one way? If yes, you need a loop. - Forgetting to remove the outgoing element. When
leftadvances, its element must leave your frequency map or set. A stale count makes a valid window look invalid and quietly shortens your answer. - Inverting longest and shortest problems. For "longest", you grow the window, and when it is valid you record the answer and keep growing. For "shortest", the skeleton is different: grow until the window is valid, then shrink while it stays valid. Record the length while the window is still valid, then shrink — never after moving
left. Mixing these up produces plausible-looking wrong answers. - Testing only the happy path. Run empty input, a single element, all-identical elements, and a case where the whole input is the answer. These four checks catch most index and count bugs.
A useful habit: after writing the loop, read it back and ask "what is true here?" at the start of each pass. If you cannot answer, the invariant has drifted.
Practising Sliding Window Questions Honestly
Memorising solutions to a handful of sliding window interview questions does not survive a follow-up. What survives is being able to rebuild the solution from the invariant. So build a short list of variants — fixed size, longest valid window, shortest valid window, at most k distinct — and re-derive each one from scratch, out loud, without looking at a solution first.
The reasoning is what is being assessed, which means practice should be spoken, not just typed. Explain the pattern to an empty room, or to a practice partner, and notice the exact sentence where your explanation goes vague. That sentence is your next thing to fix. A mock or practice session is useful mainly because it gives you a record of where the explanation wobbled, which you can review afterwards.
Keep the practice honest. The goal is to be able to solve and explain the problem yourself, not to have an answer ready to consult during an interview. Practising until the reasoning is yours is the whole point; anything else defeats it.
Before You Walk In
The sliding window coding interview rewards a clear invariant more than a good memory. Name the window, state what must be true at the start of each pass, explain why the left pointer never needs to move backwards, and give the amortised argument in one sentence. Do that and the follow-up questions become easy rather than threatening.
Start with one problem you already know, close the solution, and re-derive it out loud from the invariant. Rehearse the narration until the invariant sentence comes out without hesitation.
Frequently asked questions
How do I know whether a problem needs a sliding window or two pointers?
Sliding window maintains a contiguous range and a validity condition on that range. Two pointers on a sorted array usually moves both pointers toward each other to find a pair or a target, and the ordering of the input does the work. If the answer is a contiguous subarray or substring and you can check validity incrementally, it is a window. If the input can be sorted and you are matching elements against each other, it is two pointers.
Why is the sliding window solution O(n) when there is a loop inside a loop?
Because the inner shrink loop does not run from scratch each time. Each element enters the window once, when the right pointer passes it, and leaves at most once, when the left pointer passes it. The total number of pointer moves across the whole run is bounded by about twice the input length, so the work is linear even though the code has nested loops.
What should I say if I recognise the pattern but cannot finish the code?
Say what you do know: the invariant, the update rule, and the complexity. Then write the skeleton and fill in the parts you are sure about. A clearly stated invariant with a partial implementation shows your reasoning, which is what the exercise is testing.
Do I need to memorise sliding window solutions for common interview questions?
No, and memorising tends to fail as soon as the question is varied. Learn the skeleton and the invariant, then re-derive each variant from it. Fixed-size, longest valid, shortest valid and at-most-k-distinct are all the same structure with a different validity check.
How do I explain the window invariant clearly under time pressure?
Prepare one sentence in advance: at the top of each iteration, the window is valid and contains the best answer ending at the right pointer. Say it before you start typing, and repeat it whenever you are interrupted. Practising that sentence aloud is what makes it available when you are nervous.
Rehearse your sliding window explanation out loud and review where it got vague.