找到100个最接近原点的恒星的算法

时间:2012-02-08 22:12:19

标签: algorithm

首先让我说出正确的问题:

问:有一个文件包含超过一百万个点(x,y),每个点代表一个星号。在(a,b)有一个行星地球。现在,任务是建立一个算法,将100颗最接近的恒星归还地球。您的算法的时间和空间复杂性是什么。

在各种采访中已经多次询问过这个问题。我试着查找答案,但找不到满意的答案。

我认为可能使用大小为100的最大堆的一种方法。计算每个星的距离并检查距离是否小于最大堆的根。如果是,请将其替换为root并调用heapify。

还有其他更好/更快的答案吗?

P.S:这不是一个家庭作业问题。

5 个答案:

答案 0 :(得分:27)

你实际上可以在时间O(n)和空间O(k)中做到这一点,其中k是你想要的最近点的数量,使用一个非常聪明的技巧。

selection problem 如下:给定一个元素数组和一些索引i,重新排列数组的元素,使第i个元素在正确的位置,所有元素都更小比第i个元素在左边,所有大于第i个元素的元素都在右边。例如,给定数组

40  10  00  30  20

如果我尝试根据索引2(零索引)进行选择,则一个结果可能是

10  00  20  40  30

由于索引2(20)处的元素位于正确位置,因此左侧的元素小于20,右侧的元素大于20。

事实证明,由于这不是一个比实际排序数组更严格的要求,因此可以在时间O(n)中执行此操作,其中n是数组元素的数量。这样做需要一些复杂的算法,如median-of-medians算法,但实际上是O(n)时间。

那么你怎么在这里使用它?一种选择是将文件中的所有n个元素加载到数组中,然后使用选择算法在O(n)时间和O(n)空间(此处,k = 100)中选择前k个。

但实际上你可以比这更好!对于你想要的任何常数k,保持2k元素的缓冲区。将2k元素从文件加载到数组中,然后使用选择算法重新排列它,使得最小的k个元素位于数组的左半部分,最大的元素位于右侧,然后丢弃最大的k个元素(它们可以' t是k个最近点中的任何一个)。现在,将更多元素从文件加载到缓冲区中并再次执行此选择,并重复此操作直到您处理完文件的每一行。每次进行选择时,都会丢弃缓冲区中最大的k个元素,并保留到目前为止看到的k个最近点。因此,在最后,您可以最后一次选择前k个元素并找到前k个。

新方法的复杂性是什么?那么,你正在使用O(k)内存作为缓冲区和选择算法。最后,在大小为O(k)的缓冲区上调用select总共O(n / k)次,因为在读取k个新元素后调用select。由于在大小为O(k)的缓冲区上选择花费时间O(k),因此这里的总运行时间是O(n + k)。如果k = O(n)(合理的假设),则需要时间O(n),空间O(k)。

希望这有帮助!

答案 1 :(得分:1)

要详细说明MaxHeap解决方案,您将使用文件中的前k个元素构建最大堆(在本例中为k = 100)。

最大堆的关键是它与地球的距离(a,b)。可以使用以下公式计算2d平面上2个点之间的距离:

dist = (x1,y1) to (x2,y2) = square_root((x2 - x1)^2 + (y2 - y1)^2); 

这将花费O(k)时间来构建。对于从k到n的每个后续元素。即(n - k)个元素,你需要从地球获取它的距离,并将它与最大堆的顶部进行比较。如果要插入的新元素比max-heap的顶部更靠近地球,则替换max-heap的顶部并在堆的新根上调用heapify。

这将花费O((n-k)logk)时间来完成。 最后,我们将只剩下max-heap中的k个元素。您可以调用heapify k次来返回所有这些k元素。这是另一个O(klogk)。

总时间复杂度为O(k +(n-k)logk + klogk)。

答案 2 :(得分:0)

这是一个着名的问题,有很多解决方案: http://en.wikipedia.org/wiki/K-nearest_neighbor_algorithm

如果你没有发现它有用,还有一些其他资源,如Rurk的计算几何书。

答案 3 :(得分:0)

您的算法是正确的。请记住,程序的时间复杂度为O(n.log 100)= O(n),除非找到的最近点的数量可能不同。

答案 4 :(得分:0)

import sys,os,csv

iFile=open('./file_copd.out','rU')
earth = [0,0]



##getDistance return distance given two stars
def getDistance(star1,star2):
    return sqrt((star1[0]-star2[0])**2 +(star1[1]-star2[1])**2 )


##diction dict_galaxy looks like this  {key,distance}  key is the seq assign to each star, value is a list [distance,its cordinance]
##{1,[distance1,[x,y]];2,[distance2,[x,y]]}
dict_galaxy={}
#list_galaxy=[]
count = 0
sour=iFile.readlines()
for line in sour:
    star=line.split(',')   ##Star is a list [x,y]
    dict_galaxy[count]=[getDistance(earth,star),star]
    count++

###Now sort this dictionary based on their distance, and return you a list of keys.
list_sorted_key = sorted(dict_galaxy,key=lambda x:dict_galaxy[x][0])

print 'is this what you want %s'%(list_sorted_key[:100].to_s)
iFile.close()