最接近原点的 K 个点(K Closest Points to Origin)
LeetCode传送门973. 最接近原点的 K 个点
原题
我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。
(这里,平面上两点之间的距离是欧几里德距离。)
你可以按任何顺序返回答案。除了点坐标的顺序之外,答案确保是唯一的。
Given an array of points where points[i] = [xi, yi] 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 (i.e., √(x1 - x2)2 + (y1 - y2)2).
You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in).
Example
Input: points = [[1,3],[-2,2]], k = 1
Output: [[-2,2]]
Explanation:
The distance between (1, 3) and the origin is sqrt(10).
The distance between (-2, 2) and the origin is sqrt(8).
Since sqrt(8) < sqrt(10), (-2, 2) is closer to the origin.
We only want the closest k = 1 points from the origin, so the answer is just [[-2,2]].
Input: points = [[3,3],[5,-1],[-2,4]], k = 2
Output: [[3,3],[-2,4]]
Explanation: The answer [[-2,4],[3,3]] would also be accepted.
Constraints:
思考线
解题思路
看到最大的前K位或者最小的前K位之类的问题,本能告诉我,可以用大小顶堆来做。
稍微改写一下上一期的关于小顶堆的解法,我们这次用大顶堆来实现。
function kClosest(points: number[][], k: number): number[][] {
const maxHeap = new Heap([], (p1, p2) => {
const l1 = Math.sqrt(Math.pow(p1[0], 2) + Math.pow(p1[1], 2));
const l2 = Math.sqrt(Math.pow(p2[0], 2) + Math.pow(p2[1], 2));
return l2 - l1 > 0;
});
for(let i = 0; i < points.length;i ++) {
if(maxHeap.size() < k) {
maxHeap.offer(points[i]);
} else {
const top = maxHeap.peek();
const li = Math.sqrt(Math.pow(points[i][0], 2) + Math.pow(points[i][1], 2));
const ltop = Math.sqrt(Math.pow(top[0], 2) + Math.pow(top[1], 2));
if(ltop > li) {
maxHeap.data[0] = points[i];
maxHeap.bubbleDown(0);
}
}
}
const res = [];
while(k--) {
res.push(maxHeap.poll());
}
return res;
};
type dHash = number[]
class Heap {
data: dHash[]
comparator: (a: number[], b: number[]) => boolean
constructor(data = [], comparator) {
this.data = data;
this.comparator = comparator;
this.heapify();
}
heapify() {
if (this.size() <= 1) return;
for (let i = 1; i < this.size(); i++) {
this.bubbleUp(i);
}
}
bubbleUp(index) {
while (index > 0) {
const parent = (index - 1) >> 1;
if (this.comparator(this.data[parent], this.data[index])) {
this.swap(parent, index);
index = parent
} else {
break;
}
}
}
bubbleDown(index) {
while (index < this.size() - 1) {
const left = index * 2 + 1;
const right = index * 2 + 2;
let findIndex = index;
if (left < this.size() && this.comparator(this.data[findIndex], this.data[left])) {
findIndex = left;
}
if (right < this.size() && this.comparator(this.data[findIndex], this.data[right])) {
findIndex = right;
}
if (findIndex !== index) {
this.swap(findIndex, index);
index = findIndex;
} else {
break;
}
}
}
offer(val) {
this.data.push(val);
this.bubbleUp(this.size() - 1);
}
peek() {
return this.data[0];
}
poll() {
if (!this.size()) return null
const res = this.data.shift();
if (this.size()) {
this.data.unshift(this.data.pop());
this.bubbleDown(0)
}
return res;
}
size(): number {
return this.data.length;
}
swap(index1, index2) {
[this.data[index2], this.data[index1]] = [this.data[index1], this.data[index2]];
}
}
这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。