最接近原點的 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的值(以外行術語而言,最小值)? 有兩種不同的方法,
Sort the array from smallest to largest value, and take the first value, or
從最小值到最大值對數組進行排序,然后取第一個值, 或者
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 個點
本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。 如若轉載,請注明出處:http://www.pswp.cn/news/389161.shtml 繁體地址,請注明出處:http://hk.pswp.cn/news/389161.shtml 英文地址,請注明出處:http://en.pswp.cn/news/389161.shtml
如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!