CO3 Topic 22 of 34
Closest pair of points
Find the two nearest points among n points in the plane in O(n log n), instead of checking all n²/2 pairs: split by x, solve each half, then check only a thin strip around the dividing line.
You will be able to
- Explain the brute-force O(n²) method and why it is too slow
- Trace the divide-and-conquer algorithm: split, recurse, strip check
- Explain why each strip point needs to be compared with at most 7 others
- Derive the O(n log n) running time
Read
- Textbook 1, §33.4 Finding the closest pair of points
- Reference book 1, §17.x (computational geometry)
- Textbook 5, Ch. on divide and conquer
Watch
Intuition
An air-traffic system tracks 10,000 aircraft and must find the two closest ones every second. Checking every pair is about 50 million distance calculations. Divide and conquer cuts this to roughly n log n ≈ 130,000.
- Sort the points by x and draw a vertical line through the middle.
- Find the closest pair in the left half and in the right half (recursively). Let δ be the smaller of the two distances.
- The only pairs that could beat δ cross the line — and both points must lie within distance δ of it. Check just that narrow strip.
How it works
Strip check. Take the points with |x − line| < δ, sorted by y. For each point, compare it only with the next points whose y is less than δ above it. A geometric packing argument shows that a δ × 2δ rectangle can hold at most 8 points that are δ apart, so each point is compared with at most 7 others — the strip costs O(n), not O(n²).
Example: points (2, 3), (12, 30), (40, 50), (5, 1), (12, 10), (3, 4).
| Step | Detail |
|---|---|
| sort by x | (2,3) (3,4) (5,1) (12,10) (12,30) (40,50) |
| split | left {(2,3), (3,4), (5,1)}, right {(12,10), (12,30), (40,50)}; the line is x = 12 (first point of the right half) |
| left best | (2,3)–(3,4), distance √2 ≈ 1.414 |
| right best | (12,10)–(12,30), distance 20 |
| δ | 1.414 |
| strip | points with |x − 12| < 1.414: (12,10) and (12,30); they are 20 apart (≥ δ), so no crossing pair is closer |
| answer | (2, 3) and (3, 4), distance ≈ 1.414 |
Python implementation
from math import dist, inf
def brute(pts):
best = (inf, None)
for i in range(len(pts)):
for j in range(i + 1, len(pts)):
best = min(best, (dist(pts[i], pts[j]), (pts[i], pts[j])))
return best
def closest_pair(points):
"""Return (distance, (p, q)) for the closest pair, in O(n log n)."""
px = sorted(points) # by x
py = sorted(points, key=lambda p: p[1]) # by y
def solve(px, py):
n = len(px)
if n <= 3:
return brute(px)
mid = n // 2
mid_x = px[mid][0]
left = set(px[:mid])
lpy = [p for p in py if p in left] # keep both halves sorted by y
rpy = [p for p in py if p not in left]
best = min(solve(px[:mid], lpy), solve(px[mid:], rpy))
strip = [p for p in py if abs(p[0] - mid_x) < best[0]]
for i, p in enumerate(strip): # each point vs. the next few above it
for q in strip[i + 1:i + 8]:
if q[1] - p[1] >= best[0]:
break
best = min(best, (dist(p, q), (p, q)))
return best
return solve(px, py)
if __name__ == "__main__":
pts = [(2, 3), (12, 30), (40, 50), (5, 1), (12, 10), (3, 4)]
d, pair = closest_pair(pts)
print(round(d, 3), pair) # 1.414 ((2, 3), (3, 4))
(The code assumes distinct points; it keeps both halves sorted by y so each level costs O(n).)
Complexity
| Method | Time |
|---|---|
| brute force (all pairs) | Θ(n²) |
| divide and conquer, re-sorting the strip at every level | T(n) = 2T(n/2) + O(n log n) = O(n log² n) |
| divide and conquer with presorting (as above) | T(n) = 2T(n/2) + O(n) = O(n log n) |
Common mistakes
- Comparing every pair in the strip. The strip can contain all n points; only the next ≤ 7 by y are needed.
- Strip width. Include points within δ of the line on both sides (total width 2δ).
- Sorting inside every call. That adds a log factor; presort once and split the y-sorted list.
- Forgetting the base case. For 2 or 3 points, use brute force.
Problems
- Find the closest pair of (1, 1), (4, 5), (7, 7), (8, 2), (2, 9), (6, 3), (3, 4), (9, 8) by the divide-and-conquer method, showing δ and the strip at the top level.
- Lab: generate 10⁵ random points and compare the running times of
bruteandclosest_pair(try 10³ points for brute). - Explain with a picture why at most 8 points can sit in a δ × 2δ rectangle when every pair is at least δ apart.
- Adapt the algorithm to points on a line (1-D). What is the simplest O(n log n) method there?
- Lab: given cities with coordinates, report the two cities closest to each other.
Quiz
GATE-style practice
Questions in the GATE CSE formats: MCQ (one correct option), MSQ (one or more correct options) and NAT (type a number). Each comes with a full worked solution. These are original practice questions, not past papers; for the real thing, see the official GATE site and its previous question papers.