101 Logo
onenoughtone

Closest Pair of Points Pattern

What is the Closest Pair of Points Problem?

The Closest Pair of Points problem asks us to find the pair of points with the smallest distance between them in a set of points in a plane.

While this can be solved in O(n²) time using a brute force approach, divide and conquer allows us to solve it in O(n log n) time.

Key Steps

  1. Sort Points: Sort all points by their x-coordinates
  2. Divide: Split the points into two equal halves by a vertical line
  3. Conquer: Recursively find the closest pairs in each half
  4. Combine: Find the closest pair that spans the dividing line and compare with the closest pairs from each half

Implementation

Here's an implementation of the closest pair of points algorithm:

function closestPair(points) { // Sort points by x-coordinate points.sort((a, b) => a.x - b.x); // Find the closest pair recursively return closestPairRecursive(points, 0, points.length - 1); } function closestPairRecursive(points, start, end) { // Base case: If there are 2 or 3 points, solve by brute force if (end - start <= 2) { return bruteForceClosestPair(points, start, end); } // Divide: Find the middle point const mid = Math.floor((start + end) / 2); const midPoint = points[mid]; // Conquer: Recursively find the closest pairs in left and right halves const leftClosest = closestPairRecursive(points, start, mid); const rightClosest = closestPairRecursive(points, mid + 1, end); // Find the minimum distance from left and right halves let minDist = Math.min(leftClosest.distance, rightClosest.distance); let closestPair = leftClosest.distance <= rightClosest.distance ? leftClosest : rightClosest; // Combine: Check if there's a closer pair that spans the dividing line const strip = []; // Collect points that are within minDist of the dividing line for (let i = start; i <= end; i++) { if (Math.abs(points[i].x - midPoint.x) < minDist) { strip.push(points[i]); } } // Sort the strip by y-coordinate strip.sort((a, b) => a.y - b.y); // Check each point in the strip and compare it with at most 7 points ahead for (let i = 0; i < strip.length; i++) { for (let j = i + 1; j < strip.length && j - i < 8; j++) { const dist = distance(strip[i], strip[j]); if (dist < minDist) { minDist = dist; closestPair = { point1: strip[i], point2: strip[j], distance: dist }; } } } return closestPair; } function bruteForceClosestPair(points, start, end) { let minDist = Infinity; let closestPair = null; for (let i = start; i <= end; i++) { for (let j = i + 1; j <= end; j++) { const dist = distance(points[i], points[j]); if (dist < minDist) { minDist = dist; closestPair = { point1: points[i], point2: points[j], distance: dist }; } } } return closestPair; } function distance(p1, p2) { return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)); }

Time and Space Complexity

Time Complexity:

O(n log n), where n is the number of points.

Space Complexity:

O(n) for storing the points and the strip.

Key Insight: The Strip

The key insight in this algorithm is that we only need to check points that are within the minimum distance (found so far) of the dividing line.

Furthermore, for each point in the strip, we only need to check at most 7 points ahead of it (when sorted by y-coordinate). This is because any other points would be farther than the minimum distance we've already found.

This optimization reduces the combine step from O(n²) to O(n), resulting in an overall time complexity of O(n log n).

IntroVisualizePatternsPractice
101 Logo
onenoughtone