Two Pointers Pattern
Learn when to move two indices toward (or across) each other over a sequence, instead of reaching for a hash map — and when a window or map is the better fit.
0/5 practice problems solved
Recognizing the pattern
Reach for it when you need to
- the input is sorted, or can be sorted without losing what you need;
- you are comparing or combining a value near the start with one near the end;
- you need to remove/partition elements in place without extra memory;
- a brute-force pair scan is O(n²) but one monotonic property lets both ends move only forward.
Don't use it when
- Unsorted input where the answer needs arbitrary-index lookups — a hash map (Arrays & Hashing) is faster to reach for.
- A contiguous range whose size changes — that's Sliding Window, not two fixed pointers.
- You need every pair, not just the ones a monotonic move can skip.
- The relationship between elements isn't monotonic in either pointer's direction.
Core mental model
Two pointers only pays off when moving one of them can never miss a better answer. Before advancing the worse side, you must be able to prove no answer using the current worse index and any position past the other pointer could beat what you've already seen — that's what lets you discard a whole side in one step instead of scanning it.
Visual trace
Container With Most Water: heights [1, 8, 6, 2, 5, 4, 8, 3, 7]. The shorter side is always moved, since it caps the area and the wall behind it can only help.
Worked example: Container With Most Water
heights = [1, 8, 6, 2, 5, 4, 8, 3, 7]. Track the best area seen while l and r converge.
| l / r | min height | width | area | move |
|---|---|---|---|---|
| 0 / 8 | 1 | 8 | 8 | move l (shorter) |
| Key step: 1 / 8 | 7 | 7 | 49 (best) | move r (shorter) |
| 1 / 7 | 3 | 6 | 18 | move r (shorter) |
Invariant: Before moving a pointer, every skipped position on that side is provably no better: the wall height caps the area, and the other wall cannot get any farther away.
Reusable template
The shape to adapt for a new problem in this pattern.
python
Common mistakes
- Moving the taller wall instead of the shorter one (loses the proof that no skipped index could help).
- Forgetting to update the running best before moving a pointer.
- Using two pointers on unsorted data where the monotonic property doesn't actually hold.
- Off-by-one loop bounds — using <= when l and r must never cross the same index twice.
- Reaching for two pointers when the window size (not two independent ends) is what's actually changing — that's Sliding Window.
Practice: easy → medium → timed check
Solve in order; each step adds one decision to the same pattern.
1. Palindrome String
EasyNot solved yetConverge from both ends
2. Is Subsequence
EasyNot solved yetTwo pointers, different speeds
3. Move Zeroes
EasyNot solved yetIn-place partition pointer
4. Container With Most Water
MediumNot solved yetDiscard the shorter wall
5. Trapping Rain Water
HardNot solved yetTrack max-so-far from both sides
Final timed check
Run a 30-minute mock covering this pattern; state the invariant before coding, then finish with complexity and edge cases.
Next lesson
Sliding Window