要求
我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。
(这里,平面上两点之间的距离是欧几里德距离。)
你可以按任何顺序返回答案。除了点坐标的顺序之外,答案确保是唯一的。
示例 1:
输入: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]]。
示例 2:
输入:points = [[3,3],[5,-1],[-2,4]], K = 2
输出:[[3,3],[-2,4]]
(答案 [[-2,4],[3,3]] 也会被接受。)
提示:
- 1 <= K <= points.length <= 10000
- -10000 < points[i][0] < 10000
- -10000 < points[i][1] < 10000
核心代码
class Solution:
def kClosest(self, points: List[List[int]], k: int) -> List[List[int]]:
return sorted(points,key=lambda x:x[0] ** 2 + x[1] ** 2)[:k]
第二种解法
class Solution:
def kClosest(self, points: List[List[int]], k: int) -> List[List[int]]:
from heapq import heapify,heappop,heappush
distance = []
heapify(distance)
for index,(i,j) in enumerate(points):
heappush(distance,(i ** 2 + j ** 2,index))
res = []
while k:
k -= 1
_,idx = heappop(distance)
res.append(points[idx])
return res
第三种解法
class Solution:
def kClosest(self, points: List[List[int]], k: int) -> List[List[int]]:
from heapq import heapify,heappop,heappush
max_heap = []
for point in points:
x = point[0]
y = point[1]
distance = x ** 2 + y ** 2
if len(max_heap) < k:
heappush(max_heap,(-distance,(x,y)))
elif -max_heap[0][0] > distance:
heappop(max_heap)
heappush(max_heap,(-distance,(x,y)))
return [point for distance,point in max_heap]
解题思路:第一种解法:我们直接使用sorted按照距离进行排序,排好序取前k个值;第二种解法:TopK 就上堆,可以直接建立最小堆,然后以距离为key,让所有的点入堆,然后从最小堆里Pop K次。本质上跟排序是一样,时间复杂度:O(NlogN)
,空间复杂度:O(N)
第三种解法:最小堆很麻瓜,因为把所有的点都push进堆了,再pop K次取前K个最小的。而实际上只需要 size 为 K 的堆就够了。开一个size为K的最大堆,维护最大堆里的点为目前的前K个距离原点最近的点就够了。遍历整个points 数组,对于每个点,如果堆没满,新的点直接入堆,如果堆没满,新的点和堆顶元素进行比较,如果新的点距离更远,则说明它必定不可能是答案中包含的点。否则,说明它有可能是答案中包含的点, 让它入堆,然后pop掉调整后的堆顶元素,因为要维护最大堆的size为K。时间复杂度:O(NlogK)
,空间复杂度:O(K)
Follow Up(思考): 如果K很小,可以怎么搞? 我的想法是:
如果K非常小,比如1, 2, 3之类的,
完全可以用找数组最大数,第二大的数之类的一次扫描法来解,不需要额外开堆,
这样时间复杂度是O(N), 空间复杂度是O(1)