Pattern 02 of 20
Two Pointers
Walk two indices towards each other, or one behind the other, to avoid a nested loop.
When to use it
- The input is sorted, or sorting it does not lose information
- You compare elements from both ends (palindromes, pair sums)
- You must rearrange an array in place
The idea
Two indices move through the array under a rule that never needs to look back. Because each pointer only advances, the whole scan is linear, and order (usually sorting) tells you which pointer to move.
Typical cost O(n) time after an optional O(n log n) sort, O(1) extra space.
How it works
Two pointers replace a pair of nested loops with two indices that only ever move forward (or inward). The trick is a rule that tells you, after one comparison, which pointer can safely advance without skipping a possible answer.
With a sorted array and pointers at both ends, the rule comes from order: if the sum is too small, the left element can never be part of a solution with anything to the right, so it is discarded. Each step rules out a whole row of the brute-force grid, which is why the scan is linear.
The second shape is reader and writer: a fast pointer reads every element while a slow pointer marks where the next kept element goes. This is how you remove, compact or partition in place with O(1) memory.
Spot it when the input is sorted, when you compare from both ends (palindromes, containers), or when the problem says 'in place'. If the input is unsorted but order does not matter, sorting first is often the move that unlocks it.
How to attack it
- 1Check whether the array is sorted, or whether sorting it loses nothing the answer needs.
- 2Pick the shape: opposite ends moving inward, or slow writer and fast reader.
- 3State the movement rule and why it never skips a valid answer.
- 4Define the loop condition precisely (left < right versus left <= right).
- 5Handle duplicates explicitly if the answer must be unique.
Template
A skeleton to adapt, not a solution to paste. Write it from memory a few times.
def pair_with_sum(nums, target):
# nums must be sorted. Pointers start at both ends and move inward.
left, right = 0, len(nums) - 1
while left < right:
total = nums[left] + nums[right]
if total == target:
return [left, right]
if total < target:
left += 1 # need a bigger sum: discard the smallest
else:
right -= 1 # need a smaller sum: discard the largest
return []
def compact(nums, keep):
# Slow pointer 'write' marks where the next kept element goes.
write = 0
for read in range(len(nums)):
if keep(nums[read]):
nums[write] = nums[read]
write += 1
return write # new logical lengthVariants
- Opposite ends
- Pair sums in sorted arrays, palindrome checks, container-with-most-water style problems where you move the weaker side.
- Reader and writer
- Remove elements, deduplicate a sorted array or move zeros to the end in place, keeping relative order.
- Fix one, scan two
- For triplets, fix the first element in a loop and run opposite-end pointers on the rest: O(n²) instead of O(n³).
- Two sequences
- One pointer per array to merge sorted lists, check a subsequence, or intersect two sorted inputs.
- Three-way partition
- Low, mid and high pointers split an array into three groups in one pass, as in sorting an array of three colors.
Pitfalls
- Applying opposite-end pointers to unsorted input, where the movement rule no longer holds.
- Skipping duplicates before recording an answer instead of after, or skipping them on only one side.
- Using left <= right when an element must not pair with itself.
- Sorting when the problem asks for original indices, without keeping the indices alongside the values.
- Moving both pointers on every step when the rule says only one should move.
What it costs
| Operation | Cost |
|---|---|
| Opposite-end scan | O(n) time, O(1) space |
| Sort first | O(n log n) time, O(1) to O(n) space depending on the sort |
| Fix one plus two pointers (triplets) | O(n²) time |
| Reader and writer compaction | O(n) time, O(1) space |
30 Two Pointers problems
Easiest first. Problems marked Free can be solved without Pro.
- 1Mirror Phrase CheckFreeEasy
- 2Sorted Ledger PairFreeEasy
- 3Merge Two Sorted FeedsFreeEasy
- 4Sorted Squares of ReadingsEasy
- 5Push Zeros to the BackEasy
- 6Vowel MirrorEasy
- 7Hidden in OrderEasy
- 8Typed With BackspacesEasy
- 9Common ReadingsEasy
- 10Keep At Most Two CopiesMedium
- 11Triplets That Hit the TargetMedium
- 12Widest ReservoirMedium
- 13Three-Bin SortMedium
- 14One Deletion PalindromeMedium
- 15Count Pairs Under BudgetMedium
- 16Closest Triplet SumMedium
- 17Quadruplets That Hit the TargetMedium
- 18Fewest RaftsMedium
- 19Triangle-Ready TripletsMedium
- 20Longest RidgeMedium
- 21Shortest Unsorted WindowMedium
- 22Closest Across Three ListsMedium
- 23Schedule OverlapsMedium
- 24Next ArrangementMedium
- 25Rainwater Between WallsHard
- 26Best Span Around a DayHard
- 27Shortest Cut to SortHard
- 28Shortest Window Holding a SequenceHard
- 29K-th Smallest GapHard
- 30Mirrored ChunksHard
Solve them in the browser, in Python or JavaScript.