昨天我读了一个问题,可以通过稍加修改将其转化为以下问题:
点的坐标由2D空间中的(x,y)表示。
输入:点数组ARRAY = (x1, y1), (x2, y2), (x3, y3), ..., (xn, yn)
和另一个点D = (xi, yi)
在ARRAY
中找到距离D
最近的点。
说“最近”,我指的是Euclidian distance。
有一个明显的解决方案:遍历ARRAY
中的每个点并计算其与D
的欧几里德距离。然后,找到最短的距离。这可以在O(N)时间内完成。
我们可以在O(logN)中做得更快吗?我试图使用分而治之的方法,但尚未得出具体的想法。
问题的推广:如何在K维空间中找到最近的点?我们能否在低于O(N)的情况下做到这一点?
答案 0 :(得分:9)
如果数组没有以任何方式排序,那么就不可能比O(n)更快地进行排序,因为你必须检查每个点以确保它不比你到目前为止找到的任何点更近。
您可以进行一些预处理来对点进行排序或将它们打包成某种结构,然后对该结构进行搜索。在这种情况下,虽然预处理步骤可能比O(n)慢,但是单独搜索可能更快。如果你有很多要点来检查同一组点,这可能是有利的。
答案 1 :(得分:2)
您可以使用Bounding Volume Hierarchy。尽管如此,这并没有改善最坏情况的复杂性,也没有直接导致精确的解决方案。
答案 2 :(得分:2)
如果点在x坐标上排序,我已经在O(logN)中找到了解决方案。
它使用分而治之的方法。我根据2D空间中的x坐标划分点阵列。
考虑二维情况。
假设每个点用以下数据结构表示:
class Point {
public float getX();
public float getY();
}
我们有两个输入:点阵列ARRAY
,另一个点D
。
最初,我们希望将ARRAY
分为两部分:D
左侧的那些点,这些点位于D
的“右侧”
int pivotIndex = partition(array, 0, array.length() - 1, d);
分区后,索引小于pivotIndex
的点的x坐标小于d.getX()
;索引等于或大于pivotIndex
的点的x坐标等于或大于d.getX()
。
如果所有点都位于D
的左侧,则pivotIndex
将为array.length() - 1
。如果所有点都位于D
的右侧,则pivotIndex
将为-1
。如果某些点位于D
的左侧,而某些点位于D
的右侧,则pivotIndex
将介于0
和array.length() - 1
之间。对于具有与D
相同的x坐标的点,它们被视为在“右”侧。
现在,下一步是搜索每个分区上最近的点:
Point p1 = getNearestDot(array, 0, pivotIndex, d);
Point p2 = getNearestDot(array, pivotIndex + 1, array.length() - 1, d);
if (p1 == null) return p2;
if (p2 == null) return p1;
return nearer(p1, p2, d);
ARRAY
中的所有点都可能位于D
的左侧,在这种情况下p2将为空。同样,如果ARRAY
中的所有点都位于D
的右侧,则p1将为空。
getNearestDot
的算法如下:
// Find the nearest dot in array[low...high] inclusive which is closest to point d
Point getNearestDot(Point[] array, int low, int high, Point d) {
if (low > high)
return null;
if (low == high)
return array[low];
int middle = low + (high - low) >> 1;
Point p1 = getNearestDot(array, low, middle, d);
Point p2 = getNearestDot(array, middle + 1, high, d);
if (p1 == null) return p2;
if (p2 == null) return p1;
return nearer(p1, p2, d);
}
最后,函数near(p1,p2,d)将返回p1或p2,它与d的距离更短。
答案 3 :(得分:0)
实际上,我们可以按x坐标对点进行排序,然后从x差最接近目标的点开始,然后向左和向右扫描,并在下一点的位置立即停止向一个方向扫描该直接距离的x差已经大于迄今为止找到的最小距离。 如果您将一半分成两部分,但不要丢弃任何一半,则分治征服仍然是线性的。