如同谷歌地图一样,以经度和纬度的形式给出一百万个坐标列表,您将如何将最近的k个城市打印到指定位置?
我在面试时问过这个问题。面试官说这可以在O(n)中通过使用插入排序到k来完成,而不是整理列表,即NlogN。我在网上找到了其他答案,大多数人说NLogN ......他[面试官]是否正确?
答案 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个元素(但它们不一定是排序的)。
因为在每一步你只处理一半,所以时间将是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
好。
很显然,您仍然需要将两者合并为实际距离。