leetcode_973 最接近原点的 K 个点

67 阅读2分钟

要求

我们有一个由平面上的点组成的列表 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]

image.png

解题思路:第一种解法:我们直接使用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)