最近的Pair of Points Problem最近吸引了我。更具体地说,是分治法。
此递归算法要求我将一组点分成a
和b
并计算每个块的最接近点对,然后计算这些块之间最接近的点对并返回这三个数量中的最小值。
计算块之间最接近点的算法仅通过迭代距min(a, b)
中最后一个点最多a
的最多7个点(整个集合的meadian元素)来工作)。
这两张照片代表了更好的问题。 min(a, b) = Delta
。
我了解到,如果我在l
和a
两边的b
线上有2个点,那么我最多需要在中间比较7个点剥离。
我想知道的是,如果我构建的中间条带的点距l
的距离小于Delta,我不能仅比较接下来的4点而不是7点,因为我只能拟合l
的每一侧有2个点,距离l
的Delta小于彼此的Delta?
编辑: 我也开始悬赏cs stackexchange上的一个非常类似的问题,在那里我们进行了非常有趣的讨论。因此,我将其链接为here。我们还开始了非常有见地的聊天here。
答案 0 :(得分:1)
注意:该答案已更新,以供将来参考,其依据是与accepted answer的作者@Danilo SouzaMorães和@burnabyRails进行的广泛讨论。 CS网站。原始答案的主要问题是,我假设此处使用/讨论了一些不同的算法。由于原始答案为Danilo提供了一些重要的见解,因此保留了原样。另外,如果您要阅读Danilo在回答中提到的discussion,请务必先阅读此处的介绍,以更好地理解我的意思。添加的序言部分讨论了所讨论算法的不同版本。
此算法基于两个主要思想:
O(N)
的时间内完成“组合”步骤,因为您可以证明可以对{{ 1}}时间。尽管如此,在实践中有几种方法可以实现相同的基本思想,特别是组合步骤。主要区别在于:
O(1)
完成过滤,则可以进行一些过滤而不会浪费O(N*log(N))
时间。换句话说,如果您知道优秀候选人的人数上限很强,则不必精确检查该候选人的人数。CLRS Introduction to Algorithms中算法的经典描述清楚地回答了问题1,因为您混合了“左”点和“右”点并对其进行了共同处理。至于#2,答案(对我而言)不太清楚,但可能意味着检查一些固定点数。这似乎是Danilo想到的那个版本。
我想到的算法在两点上都是不同的:它遍历“左”点并针对所有过滤的“右”候选点进行检查。显然,在编写答案以及在聊天中进行初步讨论时,我没有意识到这种差异。
这是我想到的算法的草图。
开始的步骤很常见:我们已经处理了“左”和“右”点,并知道最好的O(1)
沙发,并沿轴对它们进行了排序。我们还过滤掉了
Y
条中不存在的所有点。
外部循环是,我们经过“左”点。现在假设我们处理一个,我们称其为“左点”。此外,我们在必要时半独立地遍历“正确”的点,以移动“起始位置”(请参阅步骤2)。
对于每个左点,请从右点的最后一个起始位置上移,然后递增起始位置,直到我们到达±
(或更确切地说)与根据{{1}}轴的左点。 (注意:“左”点和“右”点之间的分隔使得必须从
-
开始)
现在从该起始位置继续向上,并计算到Y
之前所有点与当前左点的距离。
在步骤#2和#3中进行的过滤使它“与数据相关”。在此实现中的权衡是,您进行的距离检查更少,但需要进行更多的-
检查。此外,代码的争论也更复杂。
为什么这种组合算法在+
中有效?出于同样的原因,在矩形Y
中可以容纳多少个点上也有固定的界限(即O(N)
),因此,两点之间的距离至少为O(1)
。这意味着在步骤#3中将进行x2
个检查。实际上,使用此算法检查的所有距离都将由CLRS版本检查,并且根据数据还可能会检查更多距离。
步骤2的摊销成本也为,因为整个外部循环中步骤2的总成本为
O(1)
:您显然无法将起始位置进一步提高总共比“正确点”还多。
即使在算法的CLRS版本中,您也可以轻松地对#2做出不同的决定。关键步骤的说明为:
- 对于数组
O(1)
中的每个点O(n)
,该算法尝试在p
的{{1}}单位内的Y′
中查找点。正如我们将很快看到的,仅需要考虑Y′
之后的δ
中的7个点。该算法计算从p到每个p
点的距离,并跟踪在Y′
的所有点对中找到的最接近对距离p
很容易对其进行修改,以不检查7
点,而是先检查δ′
的差是否小于Y′
。显然,您仍然可以保证检查的点数不超过7
。再次需要权衡的是,您进行的距离检查较少,但进行了一些Y
差异检查。取决于您的数据和硬件上不同操作的相对性能,这可能是一个好选择或一个坏选择。
如果不需要查找所有具有最小距离的对,则可以在过滤时安全地使用 <=`
在具有浮点数表示形式的实际硬件世界中,7
的概念尚不清楚。通常,无论如何,您都需要检查类似Y
的内容。
我的反例背后的想法(针对另一种算法):您不必将所有点都放在边缘。侧面为<`` instead of
的等边三角形可以拟合为大小为=
的正方形(这是表示abs(a - b) < έ
的另一种方式)
我认为您没有正确理解该算法中该常数的含义。实际上,您不会检查
-έ
或<
或任何固定数量的点,而是沿着7
轴上(或下)并检查落入相应矩形中的点。很容易就有4
这样的观点。对于算法在承诺的7
时间内起作用而言,真正重要的是,在该步骤检查的点数上有一个固定上限。只要您能证明,任何恒定上限都将起作用。换句话说,重要的是该步骤是Y
,而不是特定的常数。 0
只是相对容易证明的一个而已。
我相信O(n*log(n))
的实际原因是,在实际的硬件上,您无法对浮点数据类型中的距离进行精确的计算,因此一定会产生一些舍入误差。这就是为什么使用O(n)
代替7
并不实际的原因。
最后,假设您可以可靠地执行7
,那么我不认为<
是正确的界限。假设<=
。假设“左”点为4
,因此它的“右” <
矩形为 = 1
和(-0.0001; 0)
。考虑以下5个点(想法是:在拐角处几乎有4个点正好适合矩形<
及其之间的距离0 <= x < 1
,第5个点位于矩形的中心):>
-1 < y < 1
= <
>
= P1
(0.001; 0.999)
= P2
(0.999; 0.93)
= P3
(0.001; -0.999)
= P4
请注意,这5个点之间的距离应大于(0.999; -0.93)
,其中一些距离“左”点可能小于P5
。这就是为什么我们首先检查它们的原因。
距离(0.5; 0)
(对称地)是
距离P1-P2
(对称地P3-P4
)是
sqrt(0.998^2 + 0.069^2) = sqrt(0.996004 + 0.004761) = sqrt(1.000765) > 1
距离P1-P5
(对称地P3-P5
)是
sqrt(0.499^2 + 0.999^2) = sqrt(0.249001 + 0.998001) = sqrt(1.247002) > 1
因此,您可以将P2-P5
个点放在这样的P4-P5
矩形中,该矩形明显大于sqrt(0.499^2 + 0.93^2) = sqrt(0.249001 + 0.8649) = sqrt(1.113901) > 1
。