【问题标题】:What is the most efficient way to calculate the maximum distance of two points in a list?计算列表中两点的最大距离的最有效方法是什么?
【发布时间】:2014-06-29 05:44:41
【问题描述】:

我有一个L 点列表(x, y) 和通常的欧几里得距离度量

如何在此列表中找到两点的最大距离?或者,更正式地说:我如何找到

简单的方法

解决这个问题最简单的方法似乎是尝试一切:

def find_max_dist(L):
    max_dist = d(L[0], L[1])
    for i in range(0, len(L)-1):
        for j in range(i+1, len(L):
            max_dist = max(d(L[i], L[j]), max_dist)
    return max_dist

为了使计算更快,我可以在循环中使用平方距离并在最后返回根。

这种方法的运行时间复杂度为,其中n 是列表L 的长度。 (以及恒定的空间复杂度)。

凸包

显然,没有任何算法比 O(n) 更快,因为我们必须对列表中的每个元素至少查看一次。

凸包元素之间的距离最大。但是很容易证明凸包的计算至少在O(n log n)Graham's scan 似乎做到了。但是在找到复杂的船体之后,我仍然必须获得最大距离。所以我最终会得到

def find_max_dist_graham_triv(L):
    H = Graham_scan(L)
    return find_max_dist(L)

现在,这是我不确定的一点。我认为可以这样改进:

def find_max_dist_graham_c1(L):
    H = Graham_scan(L)  # Get ordered list of convex hull points
    max_dist = d(L[0], L[1])
    for i in range(0, len(L)-1):
        loop_max_dist = 0
        for j in range(i+1, len(L):
            curr_dist = d(L[i], L[j])
            if curr_dist < loop_max_dist:
                break
            loop_max_dist = curr_dist
            max_dist = max(loop_max_dist, max_dist)

    return max_dist

这个想法是,当你取一个凸包的一个点并从它的相邻点开始时,对角线会不断增加,达到最大值,然后不断减小。不过,我不确定这是否属实。

直观地说,我会继续改进算法:一旦第一个内循环完成,我们就找到了该循环的“最长对角线”。这条对角线将所有其他船体点分隔成两个分离的集合。每条较长的对角线都必须由这两个集合中的点组成(对吗?):

def find_max_dist_graham_c1(L):
    H = Graham_scan(L)  # Get ordered list of convex hull points
    max_dist = d(L[0], L[1])  # Get a fist idea what the longest distance might be

    i = 0
    p1 = L[i]  # Grab a random point
    loop_max_dist = 0
    for j in range(1, len(L):
        curr_dist = d(L[i], L[j])
        if curr_dist < loop_max_dist:
            break
        loop_max_dist = curr_dist
        max_dist = max(loop_max_dist, max_dist)
    # Every diagonal that is longer than the best one found with L[0]
    # has to have points in both of the following two sets (correct?):
    # [1...j] and [j+1...len(L)]

    # Try to find a neighboring diagonal that is longer.
    change = True
    while change:
        change = False
        if d(L[i-1], L[j+1]) > max_dist:
            max_dist = d(L[i-1], L[j+1])
            i -= 1
            j += 1
            change = True
        elif d(L[i+1], L[j-1]) > max_dist:
            max_dist = d(L[i+1], L[j-1])
            i += 1
            j -= 1
            change = True
    return max_dist

凸包上的每个点 P 在凸包上都有一个点 Q,使得 PQ 是包括 P 在内的最长对角线。但是 P 也是 Q 的最长对角线的“端点”吗?

我真的不确定这个算法是否正确。它会在 O(n log n) 中。

我想这个问题分析得很好,所以有人可以留下一些笔记吗?

虽然我有很多子问题,但主要问题是:

找到点列表中点的最大距离的有效方法是什么?

【问题讨论】:

  • 你想找到相距最远的2个点吗?
  • @Amir:不,我想得到彼此最远的2个点的距离。
  • 两个固定点之间的距离如何变化?
  • 我认为你是在正确的轨道上。您可以使用二分搜索改进第二部分。对于凸包上的每个点,搜索距离它最大的点。即下一个点的距离和上一个点的距离小于当前点。
  • @Amir:两个固定点之间的距离不变。为什么要问?

标签: algorithm geometry big-o


【解决方案1】:

您应该查看旋转卡尺(http://en.wikipedia.org/wiki/Rotating_calipers) - 它们被广泛用于此类问题。 另外,你的假设是错误的。对于凸多边形上的一个不动点p:对角线可以先增减,再增减。至少,我遇到过这种情况。

还有一种启发式方法:选择一个点 x。找到距离它最远的 y 点。找到距离 y 最远的点 zd(z,y) 是一个很好的估计。

说明对角线的图像:

1->2:增加; 2->3 递减; 3->4 增加; 4->5 递减。图可能不准确,把3和4指向的点移到离p远一点(在同一条线上)。

【讨论】:

  • 你有启发式的参考吗?我想阅读它
【解决方案2】:

假设您的点分布均匀,您可以执行以下操作:

找到 max_xmin_x 是最大和最小 X 坐标 - (O(n))。这些值应该可以帮助您选择一个常数 k 作为当前点集的“最佳”值。 k 的不同值只会影响算法的复杂度。

考虑一个类似于矩阵的新数据结构,它是向量的向量或链表的向量,我们将其命名为structure,其中structure[i] 是对应的向量/链表(如上所述)。按如下方式填充此数据结构:structure[i] 应包含其x 坐标在[max_x+ik,max_x+(i+1)k] 范围内的点,这将需要另一个O(n) 时间和O(n) 额外空间。现在您按y 坐标对structure[i] 的每个条目进行排序。完成此操作后,计算以下点集之间的距离(蛮力)就足够了:structure[0]structure[structure.length()-1]、每个其他 structure[i] 的极值(第一个和最后一个索引的条目)。

基本上这与做凸包并开始计算凸包上的点的距离几乎相同,不同之处在于选择正确的k 可能会使其更快或更慢。具有最坏情况复杂度O(n^2) 和最佳情况复杂度O(nLg(n))。其中k 将影响排序更大的点组或使用更多点来计算之间距离的交易。

【讨论】:

  • “假设你的分数分布均匀,你可以做以下事情”——我没有。
猜你喜欢
  • 2019-02-26
  • 2020-02-02
  • 2011-01-26
  • 2020-04-07
  • 1970-01-01
  • 1970-01-01
  • 2011-07-13
  • 1970-01-01
相关资源
最近更新 更多