973. K Closest Points to Origin
mediumAsked at AtlassianK Closest Points to Origin is Atlassian's canonical heap-introduction problem. Given an array of points and an integer k, return the k points closest to (0,0) by Euclidean distance. Atlassian uses it as the first step toward more complex top-k ranking systems in their search UI.
By Alex Chen, Founder, InterviewChamp.AI · Last verified
Source citations
Public interview reports confirming this problem appears in Atlassian loops.
- Glassdoor (2026-Q1)— Atlassian SWE-II onsite reports cite K Closest Points as the warm-up heap problem before Top K Frequent Elements.
- Blind (2025-11)— Atlassian onsite threads mention K Closest Points as a recurring heap/quickselect problem.
Problem
Given an array of points where points[i] = [x_i, y_i] represents a point on the X-Y plane and an integer k, return the k closest points to the origin (0, 0). The distance between two points on the X-Y plane is the Euclidean distance. You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in).
Constraints
1 <= k <= points.length <= 10^4-10^4 <= x_i, y_i <= 10^4
Examples
Example 1
points = [[1,3],[-2,2]], k = 1[[-2,2]]Explanation: sqrt(10) > sqrt(8), so (-2,2) is closer.
Example 2
points = [[3,3],[5,-1],[-2,4]], k = 2[[3,3],[-2,4]]Approaches
1. Sort by distance, take first k
Sort the entire array by squared distance and slice the first k.
- Time
- O(n log n)
- Space
- O(n) for the sort
function kClosestSort(points, k) {
const dist = (p) => p[0] * p[0] + p[1] * p[1];
points.sort((a, b) => dist(a) - dist(b));
return points.slice(0, k);
}Tradeoff: Easiest to write; works for the LeetCode constraints. Wasteful when k << n because you do extra sort work for points you'll never return. Ship this as the warm-up, then move to heap.
2. Max-heap of size k (optimal when k << n)
Maintain a max-heap of size k. Push the first k points; for each remaining, if its distance < heap.peek().distance, pop the max and push the new point. Result = whatever stays in the heap.
- Time
- O(n log k)
- Space
- O(k)
class MaxHeap {
constructor() { this.h = []; }
size() { return this.h.length; }
peek() { return this.h[0]; }
push(v) {
this.h.push(v);
let i = this.h.length - 1;
while (i > 0) {
const p = (i - 1) >> 1;
if (this.h[p][0] >= this.h[i][0]) break;
[this.h[p], this.h[i]] = [this.h[i], this.h[p]];
i = p;
}
}
pop() {
const top = this.h[0];
const last = this.h.pop();
if (this.h.length) {
this.h[0] = last;
let i = 0;
for (;;) {
const l = 2 * i + 1;
const r = 2 * i + 2;
let m = i;
if (l < this.h.length && this.h[l][0] > this.h[m][0]) m = l;
if (r < this.h.length && this.h[r][0] > this.h[m][0]) m = r;
if (m === i) break;
[this.h[i], this.h[m]] = [this.h[m], this.h[i]];
i = m;
}
}
return top;
}
}
function kClosest(points, k) {
const heap = new MaxHeap();
for (const p of points) {
const d = p[0] * p[0] + p[1] * p[1];
if (heap.size() < k) {
heap.push([d, p]);
} else if (d < heap.peek()[0]) {
heap.pop();
heap.push([d, p]);
}
}
return heap.h.map(([, p]) => p);
}Tradeoff: True O(n log k) — better than sort when k << n. Atlassian's preferred answer. Use squared distance (no sqrt) — sqrt is monotonic, so ordering is unchanged and you skip a floating-point op per comparison.
3. Quickselect (best average, no extra structure)
Partition around a random pivot until pivot index = k. Returns the k closest in unspecified order in O(n) average time.
- Time
- O(n) average, O(n^2) worst case
- Space
- O(log n) recursion
function kClosestQuickselect(points, k) {
const dist = (p) => p[0] * p[0] + p[1] * p[1];
const partition = (lo, hi) => {
const pivotIdx = lo + Math.floor(Math.random() * (hi - lo + 1));
const pivot = dist(points[pivotIdx]);
[points[pivotIdx], points[hi]] = [points[hi], points[pivotIdx]];
let store = lo;
for (let i = lo; i < hi; i++) {
if (dist(points[i]) < pivot) {
[points[store], points[i]] = [points[i], points[store]];
store++;
}
}
[points[store], points[hi]] = [points[hi], points[store]];
return store;
};
let lo = 0, hi = points.length - 1;
while (lo < hi) {
const p = partition(lo, hi);
if (p === k) break;
if (p < k) lo = p + 1;
else hi = p - 1;
}
return points.slice(0, k);
}Tradeoff: Best average performance and zero extra memory if you can mutate the input. The worst-case is O(n^2) — random pivot mitigates but doesn't eliminate. Mention this as 'and there's a quickselect variant' at Senior+; SWE-II rounds usually stop at the heap.
Atlassian-specific tips
Atlassian interviewers always ask 'why don't you take the square root of the distance?'. Answer: 'sqrt is monotonic so it doesn't change ordering, and skipping it saves a float op per compare'. That's the question being graded — they want you to recognize the algebraic shortcut. After heap they often follow up with 'what if the points stream in and you only ever want the live top-k?' which is the same heap, just an online flavor.
Common mistakes
- Computing sqrt(x*x + y*y) — works but you lose ~2x performance and the interviewer will ask why.
- Building the heap as min-heap of size n then popping k — that's O(n + k log n) which is worse than max-heap of size k for the typical k << n case.
- Forgetting to handle k > points.length — the LeetCode constraint guarantees k <= n but the streaming variant does not.
Follow-up questions
An interviewer at Atlassian may pivot to one of these next:
- Streaming version — points arrive one-by-one; return the current top-k after each insert. Same heap.
- Top K Frequent Elements (LeetCode 347) — same heap pattern keyed on count instead of distance.
- What if the distance metric were Manhattan instead of Euclidean? Replace x*x + y*y with abs(x) + abs(y); algorithm unchanged.
Solve it now
Free. No sign-up. Python and JavaScript run instantly in your browser.
FAQ
Heap or quickselect at Atlassian?
Heap is the expected answer. Quickselect is a bonus only if you can explain the worst-case risk. At SWE-II/SWE-III the heap closes the question; mention quickselect as 'and there's an O(n) average variant' to score on the breadth axis without spending time on it.
Why max-heap and not min-heap?
You want to keep the k SMALLEST distances. A max-heap of size k lets you compare each new point to the current MAX of your kept set — if the new point is smaller, evict the max. Min-heap would force you to keep all n in the heap.
Free learning resources
Curated free links for this problem.
Practice these live with InterviewChamp.AI
Drill K Closest Points to Origin and other Atlassian interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.
Practice these live with InterviewChamp.AI →