题目
我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。平面上两点之间的距离是欧几里德距离。
示例
(转自leetcode)
输入:points = [[1,3],[-2,2]], K = 1
输出:[[-2,2]]
解释:
(1, 3) 和原点之间的距离为 sqrt(10),
(-2, 2) 和原点之间的距离为 sqrt(8),
由于 sqrt(8) < sqrt(10),(-2, 2) 离原点更近。
我们只需要距离原点最近的 K = 1 个点,所以答案就是 [[-2,2]]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/k-closest-points-to-origin
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
提示
- 初中数学中的直角斜边的公式(a平方 + b平方 = c平方)
- js内置一个API,(Math.hypot(a, b) = c).方法返回所有参数的平方和的平方根
所以
求的就是上图中的两条斜线 ```javascript 斜线 (-2, 2)到原点设为c1 斜线 (1, 3)到原点设为c2
c1 = Math.sqrt(Math.pow(-2, 2) + Math.pow(-2, 2), 2); c2 = Math.sqrt(Math.pow(1, 2) + Math.pow(3, 2), 2);
// Math.hypot来表示就是, 简便了很多 c1 = Math.hypot(-2, 2); c2 = Math.hypot(1, 3);
<a name="c7nTU"></a>
### 实现
- 使用大顶堆来写
```javascript
/**
* @param {number[][]} points
* @param {number} k
* @return {number[][]}
*/
var kClosest = function(points, k) {
const distanceMap = transform(points);
const heap = [];
distanceMap.forEach((item) => {
if (heap.length < k) {
push(heap, item);
} else {
if (heap[0].distance > item.distance) {
pop(heap);
push(heap, item);
}
}
});
return heap.map((item) => points[item.key]);
};
/**
* 将计算出点于原点的距离
*/
function transform(points) {
return points.map((point, index) => {
return {
key: index,
distance: Math.hypot(point[0], point[1]),
};
});
};
// 大顶堆
// 将距离最远的放入堆顶
// 当堆内达到指定的数量后,比较堆顶于当前推入元素大小
function pop(heap) {
if (heap.length === 0) {
return;
}
const first = heap[0];
const last = heap.pop();
if (first !== last) {
heap[0] = last;
siftDown(heap, last, 0);
}
return first;
}
function push(heap, node) {
const len = heap.length;
heap.push(node);
siftUp(heap, node, len);
}
function compare(a, b) {
return a.distance - b.distance;
};
function siftUp(
heap,
node,
i,
) {
let index = i;
while(index > 0) {
const parentIndex = (index - 1) >>> 1;
const parent = heap[parentIndex];
if (compare(node, parent) > 0) {
heap[parentIndex] = node;
heap[index] = parent;
index = parentIndex;
} else {
return;
}
}
};
function siftDown(
heap,
node,
i,
) {
const length = heap.length;
const halfIndex = length >>> 1;
let parentIndex = i;
while(parentIndex < halfIndex) {
const leftIndex = (parentIndex << 1) + 1;
const left = heap[leftIndex];
const rightIndex = leftIndex + 1;
const right = heap[rightIndex];
if (compare(left, node) > 0) {
if (rightIndex < length && compare(right, left) > 0) {
heap[rightIndex] = node;
heap[parentIndex] = right;
parentIndex = rightIndex;
} else {
heap[leftIndex] = node;
heap[parentIndex] = left;
parentIndex = leftIndex;
}
} else if (rightIndex < length && compare(right, node) > 0) {
heap[rightIndex] = node;
heap[parentIndex] = right;
parentIndex = rightIndex;
} else {
return;
}
}
};