K Closest Points to Origin Solution
Given an array of points on the X-Y plane, return the k closest points to the origin (0, 0). Distance is Euclidean. The answer may be returned in any order.
Problem Statement
Given an array of points points[i] = [x, y], return the k points closest to the origin. The Euclidean distance is √(x² + y²), but since we only compare distances, we can use x² + y² (skip the square root).
Sort by Distance — O(n log n)
Sort all points by their squared distance from the origin, then return the first k. Correct and straightforward, but sorts all n points when we only need the top-k closest.
Sorting by distance places the closest points first. Taking the first k gives the answer directly.
| Metric | Value |
|---|---|
| Time | O(n log n) |
| Space | O(1) — in-place sort (O(n) for copy) |
Max-Heap of Size k — O(n log k)
Maintain a max-heap of size k, ordered by distance. For each point: add it to the heap. If the heap exceeds size k, remove the farthest point (the root). After processing all points, the heap holds the k closest.
- Step 1: Create a max-heap ordered by squared distance (largest distance at root).
- Step 2: For each point, offer it to the heap.
- Step 3: If heap size > k, poll the root (farthest point).
- Step 4: Heap contents = the k closest points.
- "Find k closest / k smallest" → max-heap of size k.
- The inverse of "kth largest" (which uses a min-heap).
- By keeping a max-heap, the root is the worst candidate among the k best — easy to evict when a better one arrives.
- This pattern appears in LC 973, nearest-neighbor searches, and streaming top-k problems.
√a < √b ⟺ a < b for non-negative values, comparing x² + y² directly gives the same ordering as Euclidean distance — no floating-point needed.
Visual Walkthrough
Trace with points = [[3,3],[5,-1],[-2,4]], k = 2:
Code — Java & Python
Complexity Analysis
| Approach | Time | Space | Trade-off |
|---|---|---|---|
| Sort by distance | O(n log n) | O(1) | Simple; sorts everything |
| Max-Heap size k ← optimal | O(n log k) | O(k) | Only stores k points. O(log k) per point. |
| Quickselect | O(n) avg | O(1) | Partitions by distance. O(n²) worst-case. |
- We want the k closest (smallest distances).
- A max-heap of size k keeps the root as the farthest among the k best — the one most likely to be replaced.
- When a closer point arrives, it replaces the root.
- If we used a min-heap, the root would be the closest point — polling it would remove a point we want to keep.
Edge Cases & Pitfalls
| Case | Input | Why It Matters |
|---|---|---|
| k = n (all points) | [[1,0],[0,1]], k=2 | Return all points. Heap never polls. |
| k = 1 | [[1,1],[3,4]], k=1 | Heap size 1 → just the closest point. |
| Origin point | [[0,0],[1,1]], k=1 | Distance 0 is closest. Heap handles it. |
| Negative coordinates | [[-2,-3]], k=1 | Squaring makes negatives positive. d² = 4+9 = 13. |
| Equal distances | [[1,0],[0,1]], k=1 | Both have d²=1. Either is valid — answer order doesn't matter. |
| Large coordinates | [[10000,10000]] | d² = 2×10⁸ — fits in int (max ~2.1×10⁹). |
Math.sqrt(x*x + y*y) and comparing floating-point distances. This is unnecessary and introduces precision errors. Since √a < √b ⟺ a < b, compare x²+y² directly as integers — faster and exact.