给定2d点列表,找到最接近所有其他点的点

时间:2012-10-15 23:57:12

标签: algorithm language-agnostic

Input: list of 2d points (x,y) where x and y are integers.

Distance: distance is defined as the Manhattan distance. 
    ie:
    def dist(p1,p2) 
         return abs(p1.x-p2.x) + abs(p1.y - p2.y)

找到最接近所有其他点的点的有效算法是什么。

我只能想到蛮力O(n ^ 2)解决方案:

minDist=inf
bestPoint = null
for p1 in points:
    dist = 0
    for p2 in points:
        dist+=distance(p1,p2)
    minDist = min(dist,minDist)
    bestPoint = argmin(p1, bestPoint)

基本上看每一对点。

3 个答案:

答案 0 :(得分:12)

请注意,在1-D中,最小化到所有点的距离总和的点是中位数。

在二维中,问题可以在O(n log n)中解决,如下所示:

创建x坐标的排序数组,并为数组中的每个元素计算选择该坐标的“水平”成本。元素的水平成本是投影到X轴上的所有点的距离之和。这可以通过扫描阵列两次(一次从左到右,一次在反方向)以线性时间计算。类似地,创建一个y坐标的排序数组,并为数组中的每个元素计算选择该坐标的“垂直”成本。

现在,对于原始数组中的每个点,我们可以通过添加水平和垂直成本来计算O(1)时间内所有其他点的总成本。因此,我们可以在O(n)中计算最佳点。因此总运行时间为O(n log n)

答案 1 :(得分:4)

您要找的是center of mass

你基本上将所有xs'和ys'加在一起,除以整个系统的质量。 现在,你的粒子质量均匀,质量为1。

然后你所要做的就是将粒子的位置相加并除以粒子数。

说我们有p1(1,2)p2(1,1)p3(1,0)

// we sum the x's 

    bestXcord = (1+1+1)/3 = 1

//we sum the y's 

    bestYcord = (2+1)/3 = 1 

所以p2是最接近的。

在O(n)中解决

答案 2 :(得分:1)

从最初的algortihm开始,可以进行优化:

minDist=inf
bestPoint = null
for p1 in points:
    dist = 0
    for p2 in points:
        dist+=distance(p1,p2)
        //This will weed out bad points rather fast
        if dist>=minDist then continue(p1)
    /*
    //Unnecessary because of new line above
    minDist = min(dist,minDist)
    bestPoint = argmin(p1, bestPoint)
    */
    bestPoint = p1

这个想法是,尽可能快地扔掉异常值。这可以进一步改进:

  • 以启发式“内部”点开始p1循环(这首先创建一个好的minDist,所以更糟糕的点被扔得更快)
  • 使用启发式“外部”点启动p2循环(这会使dist快速上升,可能更快地触发退出条件

如果你用尺寸换取速度,你可以走另一条路线:

//assumes points are numbered 0..n
dist[]=int[n+1]; //initialized to 0
for (i=0;i<n;i++)
  for (j=i+1;j<=n;j++) {
    dist=dist(p[i], p[j]);
    dist[i]+=dist;
    dist[j]+=dist;
  }
minDist=min(dist);
bestPoint=p[argmin(dist)];

需要更多空间用于dist数组,但只计算每个距离一次。这有利于更好地适应“获得N个最佳点”的问题和计算密集型矩阵。我怀疑它在x86或x64架构上没有为曼哈顿指标带来任何好处:内存访问将严重影响计算。