K最近点。时间复杂度O(n),而不是O(nLogn)。怎么样?

时间:2016-04-11 15:57:41

标签: algorithm sorting

如同谷歌地图一样,以经度和纬度的形式给出一百万个坐标列表,您将如何将最近的k个城市打印到指定位置?

我在面试时问过这个问题。面试官说这可以在O(n)中通过使用插入排序到k来完成,而不是整理列表,即NlogN。我在网上找到了其他答案,大多数人说NLogN ......他[面试官]是否正确?

4 个答案:

答案 0 :(得分:2)

我认为,在计算距离时,您可以维护一个K元素列表。

每次有新距离时,如果它小于最大距离,请将其插入列表中,并删除最大距离。

如果使用排序数组,则此插入可以是O(k),如果使用二进制堆,则可以是O(logK)。

在最坏的情况下,您将插入n次。总的来说,它将是O(NK)或O(NlogK)。如果K足够小,则为O(N)。

答案 1 :(得分:2)

这是一种快速选择算法(https://en.wikipedia.org/wiki/Quickselect

基本上它是快速修改的 - 只要你有两半,你只能对它们中的一个进行排序:

  • 如果一半包含第k个位置 - 继续进行细分和排序
  • 如果一半完全位于第k个位置 - 无需对其进行排序,我们对这些元素不感兴趣
  • 如果一半完全位于第k个位置之前 - 无需对其进行排序,我们需要所有这些元素并且它们的顺序无关紧要

完成后,你将在数组的前k个位置拥有最接近的k个元素(但它们不一定是排序的)。

因为在每一步你只处理​​一半,所以时间将是n+n/2+n/4+n/8+...=2n(忽略常数)。

对于保证O(n),您可以随时选择一个好的支点。中位数的中位数(https://en.wikipedia.org/wiki/Median_of_medians)。

答案 2 :(得分:0)

您还可以使用具有O(N)复杂度的此算法,该算法利用“HashMap-like”数组,该数组将在给定分辨率内自动对距离进行排序。

这是Java中的伪代码:

City[] cities = //your city list
Coordinate coor = //the coordinate of interest

double resolution = 0.1, capacity = 1000;

ArrayList<City>[] cityDistances = new ArrayList<City>[(int)(capacity/resolution)];
ArrayList<City> closestCities = new ArrayList<City>();

for(City c : cities) {
    double distance = coor.getDistance(c);
    int hash = distance/resolution;

    if(cityDistances[hash] == null) cityDistances[hash] = new ArrayList<City>();
    cityDistances[hash].add(c);
}


for(int index = 0 ; closestCities.size() < 10 ; index++) {
    ArrayList<City> cList = cityDist[index];
    if(cList == null) continue;
    closestCities.addAll(cList);
}

这个想法是循环遍历城市列表,计算与感兴趣的坐标的距离,然后使用距离来确定城市应该添加到“类似HashMap”的数组cityDistances的位置。距离越小,指数越接近0 resolution越小,列表closestCities越有可能在最后一次循环后以10个城市结束。

答案 3 :(得分:0)

假设纬度和经度具有给定的数字位数,我们实际上可以使用基数排序。这似乎与韩秋的答案相似,但我不确定是否是同一答案。 Wikipedia description

  

在计算机科学中,基数排序是一种非比较型整数排序算法,该算法通过按共享相同有效位和值的单个数字对键进行分组,对带有整数键的数据进行排序。需要位置表示法,但是由于整数可以表示字符串(例如,名称或日期)和特殊格式的浮点数,所以基数排序不限于整数。基数排序可以追溯到1887年Herman Hollerith在制表机上的工作。

本文对efficiency说了以下几点:

  

与其他排序算法相比,基数排序效率的主题有些棘手,并且会引起很多误解。基数排序是否比基于比较的最佳算法效率更高,效率更低或更低,取决于所做假设的细节。基数排序复杂度为n个键的O(wn),n个键是字长为w的整数​​。有时w被表示为一个常数,这将使基数排序(对于足够大的n而言)比基于最佳比较的最佳排序算法更好,后者均执行Θ(n log n)比较以对n个键进行排序。

在您的情况下,w对应于您的纬度和经度的字长,即位数。特别是,这样可以更有效地降低坐标中的精度(位数越少)。 nlogn算法是否更有效取决于您的n和实现。渐近地,它比nlogn好。

很显然,您仍然需要将两者合并为实际距离。