Two pointers and sliding window
Two pointers is the technique that turns two nested loops into a single pass. O(n²) → O(n). It has two forms.
Opposite ends — one pointer at the start, one at the end, moving toward each other. It works on a sorted array, and its power is that each step eliminates a whole row of candidates.
Example: find a pair summing to target in a sorted array. You compute a[lo] + a[hi]:
- if the sum is too small you need it larger, so
lo++(sincea[hi]is already the largest; loweringhiwould only shrink the sum) - if the sum is too large you need it smaller, so
hi--
One pointer moves per step, so n steps in total: O(n) time, O(1) memory. Note: that beats the brute force O(n²), but if the array isn't sorted you must count the O(n log n) sort too — in which case a hash map (O(n) time, O(n) memory) may win.
Same direction — both pointers move left to right, at different speeds. The classic use is filtering an array in place: a read pointer visits everything while a write pointer only writes what is kept — giving you a filter with O(1) memory and no second array. Sliding window is a special case of this form.
Sliding window is the pattern for questions about a contiguous subarray (or substring). It comes in two kinds.
Fixed-size window — the size k is given. The trick is not to recompute the window from scratch. When it slides one step right, add the new element and remove the old one — turning O(k) work into O(1):
sum += a[right] - a[right - k]
Result: O(n) instead of O(n × k).
Variable-size window — no size is given, a condition is ("no repeats", "sum at most S", "at most 2 distinct letters"). The template is always the same and worth memorising:
- move
rightone step and add the element to the window - while the window violates the condition, move
leftright and remove elements — withwhile, notif - once the window is valid again, update the answer
That is the "shrink while invalid" template.
Why is it `O(n)`? Despite the nested while, each element enters the window once and leaves once. left never moves backwards. So the inner loop's total work cannot exceed n. Say that argument out loud in an interview — many candidates mislabel their own solution O(n²) and undersell themselves.
| Signal in the problem | Variant | Key detail |
|---|---|---|
| "A pair/triple summing to X in a sorted array" | Opposite-ends two pointers | Sum too small → `lo++`, too large → `hi--`; `O(n)` time, `O(1)` memory |
| "Is it a palindrome", "reverse the array" | Opposite-ends two pointers | Compare/swap until they meet in the middle |
| "Remove duplicates", "move zeros to the end" (in place) | Same direction (read/write) | `write` advances only on kept elements |
| "Maximum sum/average of K consecutive elements" | Fixed-size window | `sum += a[right] - a[right - k]` |
| "Longest substring without repeats" | Variable window | Track the window contents in a `Set`/`Map`; shrink on a repeat |
| "Shortest subarray with sum at least S" | Variable window | Shrink as soon as the condition holds and update the minimum length |
| The subset is **not contiguous** (any elements) | Sliding window does NOT apply | Think hash map, sorting, DP or backtracking |
Interview tip: the biggest trap with sliding window is applying it to a non-contiguous problem. A window only works for contiguous subarrays/substrings. On "the largest sum of any elements" a window gives the wrong answer. So before writing code, say one sentence: "The subarray has to be contiguous here — can you confirm? Then a sliding window fits." Second tip: when explaining the complexity, always deliver the line "each element enters the window once and leaves once, so despite the nested while it is O(n)."