Lesson 117 of 250
973. K Closest Points to Origin
NeetCode: K Closest Points to Origin · LeetCode: 973. K Closest Points to Origin · Difficulty: Medium
Given a list of points [x, y] and an integer k, return the k points closest to the origin (0, 0) by Euclidean distance. Any order is accepted.
Example
Input: points = [[0, 2], [2, 2]], k = 1 Output: [[0, 2]]
Input: points = [[0, 2], [2, 0], [2, 2]], k = 2 Output: [[0, 2], [2, 0]]Comparing squared distances gives the same order and avoids square roots. A squared distance is an int value that wraps silently on overflow, so large coordinates would need long.
Brute force: sort by distance
Arrays.sort with a comparator sorts an int[][] by any key. Comparator.comparingInt is used instead of subtracting two distances, because a subtraction can overflow. clone copies the outer array, so the caller's array order is unchanged.
import java.util.Arrays;
import java.util.Comparator;
class Solution {
public int[][] kClosest(int[][] points, int k) {
int[][] sorted = points.clone();
Arrays.sort(sorted, Comparator.comparingInt(p -> p[0] * p[0] + p[1] * p[1]));
return Arrays.copyOf(sorted, k);
}
}
public class Main {
public static void main(String[] args) {
Solution s = new Solution();
System.out.println(Arrays.deepToString(s.kClosest(new int[][]{{0, 2}, {2, 2}}, 1)));
System.out.println(Arrays.deepToString(s.kClosest(new int[][]{{0, 2}, {2, 0}, {2, 2}}, 2)));
}
}[[0, 2]]
[[0, 2], [2, 0]]Time: O(n log n). Space: O(n).
Optimal: max-heap of size k
Keep a max-heap of the k closest points seen so far, keyed by distance. Java's PriorityQueue is a min-heap, so the comparator (a, b) -> Integer.compare(b[0], a[0]) reverses the order. Its top is the farthest of the current best k. For each new point, add it; if the heap exceeds k, poll the top, which is the farthest and cannot be in the answer. That costs O(log k) per point.
import java.util.Arrays;
import java.util.PriorityQueue;
class Solution {
public int[][] kClosest(int[][] points, int k) {
// Each entry is {squared distance, index}. The comparator puts the farthest point on top.
PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> Integer.compare(b[0], a[0]));
for (int i = 0; i < points.length; i++) {
int[] p = points[i];
heap.add(new int[]{p[0] * p[0] + p[1] * p[1], i});
if (heap.size() > k) {
heap.poll();
}
}
int[][] result = new int[heap.size()][];
int n = 0;
for (int[] entry : heap) {
result[n++] = points[entry[1]];
}
// Sorting only makes the printed order deterministic; the heap's iteration order is not sorted.
Arrays.sort(result, (p, q) -> p[0] != q[0] ? Integer.compare(p[0], q[0]) : Integer.compare(p[1], q[1]));
return result;
}
}
public class Main {
public static void main(String[] args) {
Solution s = new Solution();
System.out.println(Arrays.deepToString(s.kClosest(new int[][]{{0, 2}, {2, 2}}, 1)));
System.out.println(Arrays.deepToString(s.kClosest(new int[][]{{0, 2}, {2, 0}, {2, 2}}, 2)));
}
}[[0, 2]]
[[0, 2], [2, 0]]Time: O(n log k). Space: O(k). The final Arrays.sort only makes the printed order deterministic; the problem accepts any order. When several points tie at the k-th distance, either choice is accepted.
