What it is
Two pointers is a family of single- or dual-pass techniques where you track two positions in an array, string, or linked list and advance them according to a rule, instead of comparing every pair with a nested loop. The two pointers might start at opposite ends and converge (classic for sorted arrays), move at different speeds (fast/slow, useful for linked lists), or both move forward while one lags to overwrite in place (in-place filtering and merging). What makes it work is that a comparison at the pointers tells you, with certainty, which pointer to move — so you never have to revisit work already done.
When it applies
- The input is sorted, or can cheaply be made sorted, and you need pairs or triples that satisfy a sum or order condition.
- You're modifying an array in place (removing, partitioning, merging) and want O(1) extra space instead of building a new array.
- You need to find something from both ends inward — the widest/tallest container, a palindrome check, water trapped between two boundaries.
- If the array is not sorted and sorting it would destroy needed information (e.g. original positions or duplicates you must count individually), two pointers usually isn't the right tool — a hash map is often the fallback.
Tells in the problem
- "In place", "O(1) extra space", and an array that is already sorted, or explicitly allowed to be reordered.
- Looking for pairs or triples that sum to (or come closest to) a target, in a sorted or sortable array.
- "n-th from the end" on a singly linked list, where you cannot look backward or know the length up front without a second pass.
- A container/area/volume phrased around two boundary walls or endpoints, where the limiting factor is always the shorter of the two.
- Preserving relative order of elements you keep, while discarding or moving others (zeros to the end, duplicates removed).
The classic mistake
The error interviewers commonly see is moving the "wrong" pointer, or moving both pointers on every step regardless of the comparison, which either misses the true answer or degrades the approach back into a nested-loop scan in disguise. It happens because the mechanical part — "advance a pointer" — is easy to write, but the proof that moving one specific pointer (not the other, not both) can never discard the true answer is the part actually being tested, and skipping that proof leads to moving pointers arbitrarily. Before coding, state the invariant out loud: "if I move this pointer inward, what class of answers am I certain I'm not losing, and why?" If you can't answer that in one sentence, you don't yet know which pointer to move.
Questions to start with
- Valid Palindrome — pointers converging from both ends is the whole algorithm, with no sum or sort involved.
- Move Zeroes — a same-direction pair (a slow "write" pointer trailing a fast "read" pointer) for in-place filtering.
- Container With Most Water — introduces the proof step: why discarding the shorter wall can never lose the optimal answer.
- Three Sum — fixes one element, then reduces the rest to the classic converging two-pointer sweep on a sorted array.
- Trapping Rain Water — the hardest of the set: the pointer you advance depends on a running comparison of both sides' maximums, not just the immediate values.