973. K Closest Points to Origin
At a Glance
- Topic: heap-priority-queue
- Pattern: Top-K / Heap
- Difficulty: Medium
- Companies: Meta, Amazon, Google, Microsoft, Apple
- Frequency: High
- LeetCode: 973
Problem (one-liner)
Given points on a plane and integer k, return the k points with smallest Euclidean distance to (0,0) (order among the k may be any).
Recognition Cues
- Closest / smallest distance → selection problem
- Avoid sorting all
npoints when onlykneeded — heap or quickselect - Distance squared avoids
sqrtfor comparisons
Diagram
At-a-glance flow (replace with problem-specific Mermaid as you refine this note). camelCase node IDs; no spaces in IDs.
Loading diagram…
Approaches
- Brute force — compute distances, sort —
O(n log n)time. - Better — max-heap of size
kover distance —O(n log k)time,O(k)space. - Optimal — same heap approach or average
O(n)quickselect on squared distance — heap solution is interview-stable.
Optimal Solution
Go
import (
"container/heap"
)
type pointDist struct {
row int
col int
square int
}
type maxHeapPoints []*pointDist
func (heapSlice maxHeapPoints) Len() int { return len(heapSlice) }
func (heapSlice maxHeapPoints) Less(left, right int) bool {
return heapSlice[left].square > heapSlice[right].square
}
func (heapSlice maxHeapPoints) Swap(left, right int) {
heapSlice[left], heapSlice[right] = heapSlice[right], heapSlice[left]
}
func (heapSlice *maxHeapPoints) Push(value any) {
*heapSlice = append(*heapSlice, value.(*pointDist))
}
func (heapSlice *maxHeapPoints) Pop() any {
old := *heapSlice
length := len(old)
value := old[length-1]
*heapSlice = old[0 : length-1]
return value
}
func kClosest(points [][]int, k int) [][]int {
maxHeap := &maxHeapPoints{}
heap.Init(maxHeap)
for _, point := range points {
row := point[0]
col := point[1]
square := row*row + col*col
heap.Push(maxHeap, &pointDist{row: row, col: col, square: square})
if maxHeap.Len() > k {
heap.Pop(maxHeap)
}
}
result := make([][]int, 0, k)
for maxHeap.Len() > 0 {
top := heap.Pop(maxHeap).(*pointDist)
result = append(result, []int{top.row, top.col})
}
return result
}JavaScript
class MaxHeap {
constructor(compare) {
this.data = [];
this.compare = compare;
}
size() {
return this.data.length;
}
push(item) {
this.data.push(item);
this.bubbleUp(this.data.length - 1);
}
pop() {
if (this.data.length === 0) {
return undefined;
}
const top = this.data[0];
const last = this.data.pop();
if (this.data.length > 0) {
this.data[0] = last;
this.bubbleDown(0);
}
return top;
}
peek() {
return this.data[0];
}
bubbleUp(index) {
while (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
if (this.compare(this.data[index], this.data[parentIndex]) <= 0) {
break;
}
this.swap(index, parentIndex);
index = parentIndex;
}
}
bubbleDown(index) {
const length = this.data.length;
while (true) {
const leftChild = index * 2 + 1;
const rightChild = index * 2 + 2;
let candidate = index;
if (
leftChild < length &&
this.compare(this.data[leftChild], this.data[candidate]) > 0
) {
candidate = leftChild;
}
if (
rightChild < length &&
this.compare(this.data[rightChild], this.data[candidate]) > 0
) {
candidate = rightChild;
}
if (candidate === index) {
break;
}
this.swap(index, candidate);
index = candidate;
}
}
swap(leftIndex, rightIndex) {
const temp = this.data[leftIndex];
this.data[leftIndex] = this.data[rightIndex];
this.data[rightIndex] = temp;
}
}
function kClosest(points, k) {
const distSq = (point) => point[0] * point[0] + point[1] * point[1];
const heap = new MaxHeap((leftPoint, rightPoint) =>
distSq(leftPoint) - distSq(rightPoint)
);
for (const point of points) {
heap.push(point);
if (heap.size() > k) {
heap.pop();
}
}
return heap.data;
}Walkthrough
points = [[1,3],[-2,2]], k = 1. Squared distances: 10 vs 8 → keep [-2,2].
| step | point | max-heap (size ≤ k) |
|---|---|---|
| 1 | [1,3] | {10 → [1,3]} |
| 2 | [-2,2] | push 8, pop 10 |
Invariant: Max-heap stores the k smallest distances seen; root is worst among the chosen k.
Edge Cases
k === n→ return all points- Duplicate coordinates — valid multiple entries
- Negative coordinates — square removes sign issues
Pitfalls
- Using min-heap incorrectly for "k smallest" — max-heap of size k is the classic pattern
- Using
sqrtin comparator — unnecessary; squared distance preserves order
Similar Problems
- 215. Kth Largest Element in an Array — dual problem (largest vs smallest selection)
- 703. Kth Largest Element in a Stream — streaming top-k
Variants
- K farthest points → min-heap by distance or reverse logic
- Manhattan distance — replace metric in key
Mind-Map Tags
#heap #max-heap-size-k #geometry #euclidean #top-k-smallest
Last updated on
Spotted something unclear or wrong on this page?