最接近原点的 k 个点_第K个最接近原点的位置

最接近原点的 k 个点

In this article, I will be explaining to you one of the problems that you may find when tackling questions in data structures and algorithm. You will need some basic knowledge of data structures in order to understand the optimized solution to the problem. The code in this article will be based on Python (note that Python is zero-indexed)!

在这篇文章中,我会向你解释的问题之一是解决在数据结构和算法的问题时,你可能会发现。 您将需要一些数据结构的基础知识,以了解针对该问题的优化解决方案。 本文中的代码将基于Python(请注意,Python的索引为零)!

Difficulty: ❤️️️❤️️💛Ingredient: Priority Queue (or Heap)

难度 :❤️️️❤️️💛 成分 :优先队列(或堆)

At one point of your life, you may have come across an algorithm and data structures question that goes like this:

在人生的某个时刻,您可能遇到过这样的算法和数据结构问题:

Given a non-ordered (unsorted) array of coordinates and the value of k, find the kth nearest point to the origin. The coordinates given can be be in 1D, 2D or 3D space.

给定一个无序(未排序)的坐标数组和k的值,找到离原点最近的第k个点。 给定的坐标可以在1D,2D或3D空间中。

For instance, if you have an array of 2D coordinates,

例如,如果您有2D坐标数组,

[ (1,2), (1,0), (9,8), (6,8), (3,3) ]

and also given the value of k,

并给定k的值

k = 3

You are supposed to find the 3rd set of coordinates closest to the origin (0, 0). Let’s approach this step by step.

您应该找到最接近原点(0,0)的第三组坐标 。 让我们逐步解决这个问题。

蛮力 (Brute Force)

One of the possible questions you may ask yourself, instead of kth element, how do I get the 1st element closest to the origin (where k = 1)? To simplify the problem, what if I am given 1D coordinates instead of 2D or 3D?

您可能会问自己一个可能的问题,而不是第k个元素,我如何使第一个元素最接近原点(其中k = 1)? 为了简化问题,如果给我1D坐标而不是2D或3D怎么办?

For instance, given the following array

例如,给定以下数组

[ 2, 3, 1, 5, 7, 6]

How do I get the closest value to origin 0 (in layman terms, smallest value) for 1D case? There are 2 distinct way of doing so,

对于一维情况,如何获得最接近原点0的值(以外行术语而言,最小值)? 有两种不同的方法,

  1. Sort the array from smallest to largest value, and take the first value, or

    从最小值到最大值对数组进行排序,然后取第一个值, 或者

  2. Go through every single element in the array, and record the smallest you have seen. This is as good as remembering k number of elements closest to the origin, and replace if necessary.

    遍历数组中的每个元素,并记录最小的元素。 这与记住k个最接近原点的元素以及在必要时进行替换一样好。

Both solutions actually works! But there are notable difference in the runtime complexity versus space complexity (see Big O Notation).

两种解决方案均有效! 但是,运行时复杂度与空间复杂度之间存在显着差异(请参阅Big O Notation )。

蛮力—方法1:排序 (Brute Force — Method 1: Sorting)

In the first method, it is very straightforward. You sort the array,

在第一种方法中,它非常简单。 您对数组进行排序,

[ 1, 2, 3, 5, 6, 7]

And to get the smallest element (k = 1), just get the index 0 element. What about second (k = 2) element? It will be the element at index 1.

而要获得最小的元素(k = 1),只需获取索引为0的元素即可。 第二个(k = 2)元素呢? 它将是索引1处的元素。

The code (written as a function) will look something like this:

该代码(作为函数编写)将如下所示:

def kthClosestPoint(k: int, array: list):
if k < 1:
raise Exception('Invalid k') return sorted(array)[k-1]

Depending on the sorting algorithm, you will have a typical runtime complexity of O(n log n). Unlike the above code that obtains a new sorted array behind the hood which will give you a space complexity of O(n), if you sort in-place, you will have a space complexity of O(1) instead.

根据排序算法,运行时复杂度通常为O(n log n) 。 与上面的代码在幕后获得一个新的排序数组不同,这将为您提供O(n)的空间复杂度,如果就地排序,则将具有O(1)的空间复杂度。

But is there any possibility of further improving this method in terms of runtime complexity? Probably not.

但是是否有可能在运行时复杂性方面进一步改进此方法? 可能不是。

蛮力—方法2:记住k个元素 (Brute Force — Method 2: Remember k number of elements)

Now, instead of doing a sort, what if you just keep track of k number of elements closest to the origin?

现在,不进行排序,而只是跟踪最接近原点的k个元素怎么办?

Back to the same 1D example and given k = 1,

回到相同的一维示例,给定k = 1,

[ 2, 3, 1, 5, 7, 6]

You will pick up every element in the array one by one, and remember the smallest you have seen so far! Similarly for k = 2, you will remember only the 2 smallest you have seen.

您将一个接一个地拾取数组中的每个元素,并记住到目前为止所看到的最小元素! 同样,对于k = 2,您将只记得所见过的最小的2。

Now, if you are familiar with priority queue or heap queue (I will be using heapq for Python), then you will realize that you can actually make use of this data structure to obtain k smallest elements.

现在,如果您熟悉优先级队列或堆队列(我将在Python中使用heapq ),那么您将意识到,您实际上可以利用此数据结构来获取k个最小的元素。

import heapqdef kthClosestPoint(k: int, array: list):
if k < 1:
raise Exception('Invalid k') # Convert array into heap
heapq.heapify(array) return heapq.nsmallest(k, array)

If your array length (a.k.a. heap queue) is n, using this method, you will end up with a worse case runtime complexity of O(n log n), since pushing and popping an element to a heap takes O(log n). The space complexity is O(n) if you duplicate the array or in this example code, O(1) since I am doing it in place.

如果使用此方法,如果数组长度(也就是堆队列)为n ,则最终将导致运行时复杂度为O(n log n) ,因为将元素推入和弹出到堆中需要O(log n) 。 如果您复制数组,则空间复杂度为O(n) ,或者在此示例代码中为O(1),因为我在原地执行了此操作。

优化 (Optimization)

You can actually further improve the runtime complexity of this method by limiting the heap queue to k instead of the whole array length n:

您实际上可以通过将堆队列限制为k而不是整个数组长度n来进一步提高此方法的运行时复杂度

import heapqdef kthClosestPoint(k: int, array: list):
if k < 1:
raise Exception('Invalid k') k_elements = [] for num in array:
heappush(k_elements, -num) if len(k_elements) > k:
heappop(k_elements) return [-num for num in k_elements]

Note that since heappop only removes the smallest element, one possibility is to invert the polarity of the elements i.e. positive integers will be negative and negative integers will be positive. This will force all large integers to appear small, hence only large integers will be removed from the heap queue.

请注意,由于heappop仅删除最小的元素,因此一种可能性是反转元素的极性,即正整数将为负,负整数将为正。 这将强制所有大整数看起来很小,因此只有大整数将从堆队列中删除。

The typical runtime complexity will be O(n log k), since you will be heappush-ing and heappop-ing every single element of the array, while the heap queue length is at most k. This is as bad as having the worse case scenario!

典型的运行时复杂度为O(n log k) ,因为您将对数组的每个单个元素进行强制和堆弹出,而堆队列长度最多为k。 这和更糟的情况一样糟糕!

进一步优化 (Further Optimization)

Can we further improve this for typical case? Instead of placing every element into the heap queue and removing them, can we check before we do it? Yes we can!

对于典型案例,我们可以进一步改进吗? 除了将每个元素放入堆队列并删除它们之外,我们还能在执行之前检查一下吗? 我们可以!

If we already have a heap queue of size k, we should peek at the “largest” element in the heap queue and see if our current element is larger or smaller than that, before we push an element in. If the heap queue is still smaller than length k, we can continue to push elements into it!

如果我们已经有大小为k的堆队列,我们应该在堆队列中的“最大”元素偷看 ,看看我们目前的元素比更大或更小,我们在推的元素之前,如果堆队列仍小于长度k ,我们可以继续将元素推入其中!

import heapqdef kthClosestPoint(k: int, array: list):
if k < 1:
raise Exception('Invalid k') k_elements = [] for num in array: if len(k_elements) < k or k_elements[0] < -num:
heappush(k_elements, -num) if len(k_elements) > k:
heappop(k_elements) return [-num for num in k_elements]

Similarly, if you are dealing with 2D or even 3D data, you can modify this code to accommodate them, using the exact same method.

同样,如果要处理2D甚至3D数据,则可以使用完全相同的方法修改此代码以容纳它们。

求解2D数据 (Solving for 2D Data)

Assuming you have data points in an array looking like this:

假设数组中的数据点如下所示:

[ (1, 2), (3, 5), (6, 7)]

The distance for each point to origin (0, 0) is simply expressed using Pythagoras theorem in its reduced form:

每个点到原点的距离(0,0)可以使用毕达哥拉斯定理以其简化形式简单表示:

distance = x**2 + y**2

Nothing beats looking code so by modifying the previous 1D code:

修改前面的一维代码,没有什么比看代码更好的了:

import heapqdef kthClosestPoint(k: int, array: list):
if k < 1:
raise Exception('Invalid k') k_elements = [] for x, y in array: dist = x**2, y**2 if len(k_elements) < k or k_elements[0][0] < -dist:
heappush(k_elements, (-dist, x, y)) if len(k_elements) > k:
heappop(k_elements) return [[x, y] for dist, x, y in k_elements]

If you have any feedback or anything that you wish to share, feel free to drop a comment 👇!

如果您有任何反馈或希望分享的任何内容,请随时发表评论👇!

翻译自: https://medium.com/@kevingxyz/kth-closest-points-to-origin-899c762885e0

最接近原点的 k 个点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值