Two Pointers
Two indices squeeze inward so every pair never gets checked.
- Brute force
- O(n²) — check every pair
- With the pattern
- O(n) — each pointer moves at most n times (plus O(n log n) if you must sort)
- Extra space
- O(1)
In plain English
“Two friends start at opposite ends of a bookshelf sorted by thickness, looking for two books that together fill a gap exactly. If the pair is too thick, the friend on the thick end steps inward; too thin, the friend on the thin end steps inward. They meet in the middle having looked at each book only once.”
Why it's fast
Brute force tries all n² pairs. On a sorted array, one comparison tells you which side is wrong: if nums[l] + nums[r] is too big, every pair using r with anything right of l is also too big, so r can be thrown away for good. Each step discards a whole row or column of the pair grid, so you finish in O(n).
Spot it when the problem says…
- sorted array
- find a pair (or triplet) that sums to target
- in-place, O(1) extra space
- palindrome / compare from both ends
- remove duplicates or move elements in place
- maximize area between two lines
Visualize
Two Sum II — sorted input
Find two numbers in a sorted array that add up to the target. Return their indices.
Start with the smallest (L) and largest (R) values. Target = 17.
1def two_sum_sorted(nums, target):2 left, right = 0, len(nums) - 13 while left < right:4 total = nums[left] + nums[right]5 if total == target:6 return [left, right]7 if total < target:8 left += 1 # need a bigger sum9 else:10 right -= 1 # need a smaller sum11 return []variables
- left
- 0
- right
- 7
- target
- 17
How to apply it
- 01Make sure the input is sorted (sort it if order doesn't matter to the answer).
- 02Place
l = 0andr = n - 1(or two pointers moving the same direction for in-place rewrites). - 03Compute something from
nums[l]andnums[r]and compare it to the goal. - 04Move exactly the pointer whose side can't possibly be part of a better answer.
- 05Stop when the pointers cross; for k-sum, fix one element and run two pointers on the rest.
Variations you'll meet
Opposite ends (Two Sum II)
Classic converging pointers on a sorted array — what the visualizer animates.
def two_sum(numbers: list[int], target: int) -> list[int]: l, r = 0, len(numbers) - 1 while l < r: s = numbers[l] + numbers[r] if s == target: return [l + 1, r + 1] if s < target: l += 1 # need bigger sum else: r -= 1 # need smaller sum return []3Sum (fix one + two pointers)
Sort, loop i, then run the converging pair on i+1..n-1. Skip duplicate values to avoid repeated triplets.
def three_sum(nums: list[int]) -> list[list[int]]: nums.sort() res = [] for i in range(len(nums) - 2): if i and nums[i] == nums[i - 1]: continue l, r = i + 1, len(nums) - 1 while l < r: s = nums[i] + nums[l] + nums[r] if s < 0: l += 1 elif s > 0: r -= 1 else: res.append([nums[i], nums[l], nums[r]]) l += 1 while l < r and nums[l] == nums[l - 1]: l += 1 return resSame direction (read/write pointers)
A slow write pointer and a fast read pointer compact an array in place (Move Zeroes, Remove Duplicates).
Greedy shrink (Container With Most Water)
Not sorted, but you always move the shorter wall because the taller one can never help it.
Common mistakes
- Using
l <= rand pairing an element with itself. - Applying it to an unsorted array where moving a pointer gives no information.
- In 3Sum, forgetting to skip duplicates for both
iandl, producing repeated triplets. - Moving both pointers after a match when only one should move (or vice versa) and missing answers.
- Returning 0-based indices when the problem asks for 1-based (Two Sum II).
Practice ladder
Easy → hard. Tick them off as you go.
Think you've got it?
Let the AI interviewer throw a Two Pointers problem at you and grade how you explain it.