如果给你一百万个坐标,形式上与谷歌地图的经纬度相同,那么你该如何打印出距离给定位置最近的k个城市?
我在面试中被问到这个问题。面试官说可以使用插入排序来找到最近的k个城市,时间复杂度为O(n),而不是对整个列表进行排序,时间复杂度为NlogN。我在网上找到其他答案,大多数都说时间复杂度为NLogN……他[面试官]的答案正确吗?
如果给你一百万个坐标,形式上与谷歌地图的经纬度相同,那么你该如何打印出距离给定位置最近的k个城市?
我在面试中被问到这个问题。面试官说可以使用插入排序来找到最近的k个城市,时间复杂度为O(n),而不是对整个列表进行排序,时间复杂度为NlogN。我在网上找到其他答案,大多数都说时间复杂度为NLogN……他[面试官]的答案正确吗?
n+n/2+n/4+n/8+...=2n
(忽略常数)。O(n)
,你可以总是选择一个好的枢轴,例如中位数的中位数(https://en.wikipedia.org/wiki/Median_of_medians)。假设纬度和经度有一定数量的数字,我们实际上可以使用基数排序。它似乎类似于Hanqiu的答案,但我不确定是否是同一个。维基百科描述:
在计算机科学中,基数排序是一种非比较整数排序算法,通过将具有相同有效位置和值的个别数字分组来按整数键对数据进行排序。需要一种位置表示法,但由于整数可以表示字符串(例如名称或日期)和特殊格式的浮点数,因此基数排序不仅限于整数。基数排序可以追溯到1887年赫尔曼·霍勒里斯(Herman Hollerith)在制表机上的工作。
该文章关于效率的内容如下:
与其他排序算法相比的基数排序效率问题有些棘手,容易引起很多误解。无论基数排序是否与最佳比较排序算法一样有效、不如有效或更有效,都取决于所做的假设细节。对于大小为w位的整数键值n个,基数排序的复杂度为O(wn)。有时w被视为一个常数,这将使基数排序在“足够大”的情况下比所有执行Θ(n log n)次比较以排序n个键的比较排序算法更好。w
对应于纬度和经度的字长,也就是数字的数量。特别是在您的坐标精度较低(数字较少)时,这变得更加高效。无论是否比nlogn
算法更有效,都取决于您的n
和实现方式。在渐近意义上,它比nlogn
更好。你也可以使用这个算法,它具有O(N)的复杂度,利用了一个“类HashMap”的数组,该数组会自动按照给定分辨率对距离进行排序。
以下是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);
}
这个想法是循环遍历城市列表,计算与感兴趣的坐标之间的距离,然后使用距离来确定应该将城市添加到类似于“哈希映射”的数组cityDistances
中的位置。距离越小,索引就越接近0。
resolution
越小,最后一次循环后列表closestCities
中有10个城市的可能性就越大。