2026-08-14 18:37:13 -04:00
|
|
|
|
---
|
|
|
|
|
|
title: 'Two Pointers'
|
|
|
|
|
|
description: 'Converging/parallel index walk that prunes the O(n^2) pair space using order.'
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-08-20 16:04:24 -04:00
|
|
|
|
## The idea
|
2026-08-17 14:19:02 -04:00
|
|
|
|
|
2026-08-20 16:04:24 -04:00
|
|
|
|
Checking every pair costs O(n²). That is n² boxes to open.
|
2026-08-17 14:19:02 -04:00
|
|
|
|
|
2026-08-20 16:04:24 -04:00
|
|
|
|
But if the array is **ordered**, you do not need every pair.
|
|
|
|
|
|
Put one pointer at each end. Look at the sum:
|
|
|
|
|
|
- Too small? Only a bigger left value can help. Move left in.
|
|
|
|
|
|
- Too big? Only a smaller right value can help. Move right in.
|
2026-08-17 14:19:02 -04:00
|
|
|
|
|
2026-08-20 16:04:24 -04:00
|
|
|
|
Each move kills a whole row of the pair space. O(n²) → O(n).
|
2026-08-17 14:19:02 -04:00
|
|
|
|
|
2026-08-20 16:04:24 -04:00
|
|
|
|
## The picture
|
2026-08-17 14:19:02 -04:00
|
|
|
|
|
2026-08-20 16:04:24 -04:00
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart TD
|
|
|
|
|
|
A["2 7 11 15 target 18<br/>L R"] --> B["2 + 15 = 17 < 18<br/>too small → move L right"]
|
|
|
|
|
|
B --> C["2 7 11 15<br/> L R"]
|
|
|
|
|
|
C --> D["7 + 15 = 22 > 18<br/>too big → move R left"]
|
|
|
|
|
|
D --> E["2 7 11 15<br/> L R"]
|
|
|
|
|
|
E --> F["7 + 11 = 18 ✓"]
|
2026-08-19 13:05:47 -04:00
|
|
|
|
|
2026-08-20 16:04:24 -04:00
|
|
|
|
style F fill:#2e7d32,color:#fff
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Not the same as binary search
|
|
|
|
|
|
|
|
|
|
|
|
Binary search **jumps** to the middle and discards half unseen — O(log n).
|
|
|
|
|
|
Two pointers **walks** — every element gets inspected once — O(n).
|
|
|
|
|
|
Both need order. Different moves.
|
|
|
|
|
|
|
|
|
|
|
|
## Two Sum II (LC 167) — the pure template
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
def two_sum(numbers: list[int], target: int) -> list[int]:
|
|
|
|
|
|
lo, hi = 0, len(numbers) - 1
|
|
|
|
|
|
|
|
|
|
|
|
while lo < hi:
|
|
|
|
|
|
total = numbers[lo] + numbers[hi]
|
|
|
|
|
|
if total == target:
|
|
|
|
|
|
return [lo + 1, hi + 1]
|
|
|
|
|
|
if total < target:
|
|
|
|
|
|
lo += 1 # only a bigger value helps
|
|
|
|
|
|
else:
|
|
|
|
|
|
hi -= 1 # only a smaller value helps
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Container With Most Water (LC 11) — move the shorter wall
|
|
|
|
|
|
|
|
|
|
|
|
Water = width × shorter wall.
|
|
|
|
|
|
Moving the taller wall can never help — width shrinks, height cannot grow.
|
|
|
|
|
|
So always move the shorter one. Say this proof in the interview.
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
def max_area(height: list[int]) -> int:
|
|
|
|
|
|
lo, hi = 0, len(height) - 1
|
|
|
|
|
|
best = 0
|
|
|
|
|
|
|
|
|
|
|
|
while lo < hi:
|
|
|
|
|
|
best = max(best, (hi - lo) * min(height[lo], height[hi]))
|
|
|
|
|
|
if height[lo] < height[hi]:
|
|
|
|
|
|
lo += 1
|
|
|
|
|
|
else:
|
|
|
|
|
|
hi -= 1
|
|
|
|
|
|
return best
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 3Sum (LC 15) — fix one, converge two
|
|
|
|
|
|
|
|
|
|
|
|
Sort first. Fix the smallest number. Now it is Two Sum II on the rest.
|
|
|
|
|
|
Skip duplicates at every level or you get repeat triplets.
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
def three_sum(nums: list[int]) -> list[list[int]]:
|
|
|
|
|
|
nums.sort()
|
|
|
|
|
|
result = []
|
|
|
|
|
|
|
|
|
|
|
|
for i in range(len(nums) - 2):
|
|
|
|
|
|
if i > 0 and nums[i] == nums[i - 1]:
|
|
|
|
|
|
continue # skip duplicate anchor
|
|
|
|
|
|
lo, hi = i + 1, len(nums) - 1
|
|
|
|
|
|
while lo < hi:
|
|
|
|
|
|
total = nums[i] + nums[lo] + nums[hi]
|
|
|
|
|
|
if total < 0:
|
|
|
|
|
|
lo += 1
|
|
|
|
|
|
elif total > 0:
|
|
|
|
|
|
hi -= 1
|
|
|
|
|
|
else:
|
|
|
|
|
|
result.append([nums[i], nums[lo], nums[hi]])
|
|
|
|
|
|
lo += 1
|
|
|
|
|
|
while lo < hi and nums[lo] == nums[lo - 1]:
|
|
|
|
|
|
lo += 1 # skip duplicate pair
|
|
|
|
|
|
return result
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Complexity
|
|
|
|
|
|
|
|
|
|
|
|
| | Time | Space |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| Converging pair | O(n) | O(1) |
|
|
|
|
|
|
| 3Sum | O(n²) — sort + n passes | O(1) extra |
|
|
|
|
|
|
|
|
|
|
|
|
## Close-out ritual
|
|
|
|
|
|
|
|
|
|
|
|
Before you submit, say out loud:
|
|
|
|
|
|
1. Time and space complexity.
|
|
|
|
|
|
2. One edge case trace: two elements, all duplicates, or no valid answer.
|
|
|
|
|
|
|
|
|
|
|
|
## Plan problems
|
|
|
|
|
|
|
|
|
|
|
|
**A-set:** LC 125 · 167 · 15 · 11 · 42
|
|
|
|
|
|
**B-set:** LC 392 · 977 · 189 · 80
|