换句话说,我有一个网格,其中标记了某些交点。我想找到最靠近所有标记交点的交点。也就是说,我需要找到一点,使得所有点到该点的距离之和最小。
曼哈顿距离的独特之处在于距离本身由两个独立的部分组成:x和y坐标上的距离。因此,您可以解决两个简单的任务并将它们的结果合并以获得所需的结果。
我所说的任务是:给定一条线上的点,找到使所有点到该点的绝对距离之和最小的点。如果有多个,请找出所有这些点(顺便说一句,它们总是转化为一个单段,这很容易证明)。该段由集合的(可能是两个)中位数点确定。中位数是指左右两侧的点数相等的点。如果点数是偶数,则没有这样的点,并选择两个方向上差为1的点来形成该段。
这里我添加了几个解决这个简单任务的示例:
如果线上的点像这样:
-4 | | | 0 | 2 3 4
^
解决方案只是一个点,它是2
。
如果线上的点是这样的:
-4 | | | 0 | 2 3
^---^
整个区间 [0, 2] 是这个问题的解。
你需要分别针对 x 和 y 坐标解决这个任务,然后将结果合并以获得最小距离点的矩形。
假设你想要找到到集合 (0, 6), (1, 3), (3, 5), (3, 3), (4, 7), (2, 4)
中与点最小曼哈顿距离的点。
你需要分别解决两个简单任务:
对于 x:
0 1 2 3 3 4
^-^
这里的解决方案是段落 [2, 3]
(注意这里有重复的点3
,我可能没有用最直观的方式表示)。
对于y:
3 3 4 5 6 7
^-^
这里的解决方案是段落[4, 5]
。
最终,我们得到了初始任务的解决方案公式为矩形:
2 <= x <= 3; 4 <= y <= 5
让我们谈谈复杂度。
任务的复杂度实际上与解决更简单任务的复杂度相同(因为正如已经讨论过的那样,解决方案实际上包括解决两个更简单的任务)。许多人会通过排序然后选择中位数来解决它。然而,这将导致O(nlog n)
的复杂度,其中n
是输入集合中点的数量。
如果使用更好的查找第k个元素算法(C++ STL中实现示例),可以提高效率。该算法基本上遵循与qsort相同的方法。运行时间为O(n)
。即使在两个中位数点的情况下,它仍将保持线性(需要两次运行相同的算法),因此算法的总复杂度变为O(n)
。很明显,只要输入本身具有所述的复杂度,就无法更快地解决任务。