【问题标题】:Is this algorithm a good way to determine if two arrays have same contents in same order?该算法是否是确定两个数组是否以相同顺序具有相同内容的好方法?
【发布时间】:2012-02-17 19:32:33
【问题描述】:

所以我有两个数组,每个数组都表示一个简单的封闭多边形,作为按顺序遍历的点数组。最后一个元素与第一个元素相同。我正在为任何 2 个简单的封闭多边形实现一个等于算法。

Array A would be like this [pnt1, pnt2, pnt3, pnt4, pnt5, pnt6, pnt1]
Array B would be like this [pnt2, pnt3, pnt4, pnt5, pnt6, pnt1, pnt2]
Array C would be like this [pnt2, pnt1, pnt6, pnt5, pnt4, pnt3, pnt2]
Array D would be like this [pnt1, pnt2, pnt3, pnt5, pnt6, pnt4, pnt1]

数组 A 和 B 相等,因为点的顺序相同且点相同。数组 A 和 C 相等,因为点的顺序相同(但相反),B 和 C 也是相同的原因。

数组D不等于任何其他数组,因为点遍历是乱序的。

所以我的算法如下:

1) 比较数组的长度,必须包含相同的元素数 - 恒定时间

2) 在 B 集合中找到 A[0] 为 K - 线性搜索,线性时间

3) 看看A[1] = B[K+1] 等直到A[n],线性时间

索引自然会环绕数组的末尾,可能是通过 mod 运算符。

有没有比这更好的算法?

【问题讨论】:

  • 我不认为该算法检测到 A 和 C 相同但相反。
  • @Bill True,当它失败时我需要调用它两次(反转第二个参数)或调整内部循环
  • 你能保证一个点在多边形中不会出现多次吗?如果没有,您的算法可能会给出假阴性。
  • @Weeble 点可能在多边形中出现不止一次,尽管可能性很小。然而像 [A, B, C, D, E, C, B, A, C] 这样的数组是不会发生的,所以不会有重复的循环。
  • 从您的示例中,您的所有多边形似乎都是单点集的排列。是这样吗?

标签: algorithm geometry


【解决方案1】:

总结:

  1. 删除重复的点
  2. 找到最小值的位置 i
  3. 如果 i-1 处的值低于 i+1 处的值,则反转字符串(必须考虑边缘情况,即 i=0 或 i=n-1)
  4. 旋转数组,使最小值位于头部

总复杂度:O(n)

注意:步骤 3 和 4 不是绝对必要的。从第 2 步您可以得到 location 的最小值,并从第 3 步得到 orientation。在比较两个不同的数组时,只需从最小值的 *location*s 开始比较,然后根据 orientation 移动。

例如:

[pnt1, pnt2, pnt3, pnt4, pnt5, pnt6, pnt1] -> [pnt1, pnt2, pnt3, pnt4, pnt5, pnt6] -> [pnt1, pnt2, pnt3, pnt4, pnt5, pnt6]

[pnt2, pnt3, pnt4, pnt5, pnt6, pnt1, pnt2] -> [pnt2, pnt3, pnt4, pnt5, pnt6, pnt1] -> [pnt1, pnt2, pnt3, pnt4, pnt5, pnt6]

[pnt2, pnt1, pnt6, pnt5, pnt4, pnt3, pnt2] -> [pnt2, pnt1, pnt6, pnt5, pnt4, pnt3] -> [pnt3, pnt4, pnt5, pnt6, pnt1, pnt2] -> [pnt1, pnt2, pnt3, pnt4, pnt5, pnt6]

[pnt1, pnt2, pnt3, pnt5, pnt6, pnt4, pnt1] -> [pnt1, pnt2, pnt3, pnt5, pnt6, pnt4] -> [pnt1, pnt2, pnt3, pnt5, pnt6, pnt4]

【讨论】:

  • 能否请您详细说明或提供链接并提供运行时间?
  • @PeterSmith 运行时间为 O(n),我没有链接。查看更新的解决方案,如果有不清楚的地方请告诉我。
  • 你如何在 O(n) 时间内旋转成字典顺序最小的顺序?这听起来很简单,但我很难在不枚举所有旋转的情况下看到如何做到这一点。
  • 我认为(3)是错误的。给定[1 3 2 4 5][1 5 4 2 3],你将把它们都颠倒过来,你的最终比较将失败。
  • @template:彼得的算法似乎暗示没有重复点。鉴于此,只需将最小元素旋转到第一个位置即可。
【解决方案2】:

要进行这样的比较,您可以检查一个数组是否是另一个数组的旋转(最后一个元素除外)。

首先,删除重复的元素,正如 ElKamino 指出的那样。那么基本上,你想知道是否可以通过旋转B的元素来获得A。

A=[x1, x2, ..., xk] 时,B 将具有与 A 相同的内容,当且仅当B=[x3, x4, ..., xk, x1, x2] 或类似的东西。在这种情况下,B 可以称为rotation of A。但是,这还不够,因为您还想检查订单是否相同但相反。然后,您可以对B 的反向或A 的反向应用相同的过程。

伪代码

def isSamePolygon(A, B):
    remove the last element of A and last element of B
    return isRotation(A, B) or isRotation(A, reverse(B))

def isRotation(A, B): // returns true if A is a rotation of B
    // create an array which has two copies of A.
    // e.g [a1, a2, ..., ai, a1, a2, ..., ai]
    if (size(A) != size(B))
        return false
    temp_array = concat(A, A)
    return true if temp_array contains the elements of B in the exact same order,
        false otherwise

分析

isRotation 的运行时间和空间复杂度与 max(size(A), size(B)) 的大小呈线性关系。这是因为创建 temp_array 需要 A 大小的线性时间和线性空间。同样,检查 B 是否包含在 A 中也需要线性时间来运行。

如果我错了,请纠正我,但使用此算法,您无法降低渐近复杂度。但是,您可以优化它以更快地运行。如果size(A)>size(B),您可能想要交换 A 和 B。此外;您可以同时检查相反的情况,而不是进行两次调用。

【讨论】:

    【解决方案3】:

    如果不允许预处理,这个问题是最坏的情况 Omega(N) 只是因为在另一个多边形的顶点中找到一个多边形的一个顶点可能需要 N 次比较。

    所以没有比你的算法更好的了,它在最佳时间 O(N) 内运行。 [不过,在 2 和 3 之间插入一个步骤以确定遍历顺序。]

    如果允许预处理,对于每个多边形,您可以识别 (X, Y) 字典顺序中的第一个顶点。让我们称之为主顶点。这样一来,您的算法的第 1 步将变得毫无用处,因为两个相等的多边形具有相同的主顶点,并且无需进行线性搜索。

    更好的是,您可以通过从主顶点开始计算坐标上的 CRC 来将签名与多边形相关联。然后,您只需通过比较签名即可在 O(1) 时间内以高概率检测到不同的多边形。

    【讨论】:

    • 我没有考虑过计算 CRC,如果我可以预处理这些多边形,这可能是个好主意。
    • 这里不需要高度复杂的 CRC。像 X0 + 2 Y0 + 3 X1 + 4 Y1 + 5 X2 + 6 Y2... 之类的东西就可以了。
    【解决方案4】:

    我假设“简单”是指没有孔或自相交的多边形,但它可能仅在顶点处接触自身。例如:

    这种情况在您的情况下可能无关紧要,但一些 polygon algorithms 依靠这种形状来形成构成复杂多边形的轮廓,因此能够轻松应对它们。

    在这种情况下,这两个多边形应该比较相等:

    P = ABCADEAFGAHIAJKA
    Q = FGAHIAJKABCADEAF
    

    某些给定的算法可能会忽略这一点,因为 P 中的第一个(也是词典最小的)顶点 A 被重复了。但是,只要我们知道没有重复,我们就可以毫不费力地调整算法:

    1. Q 中搜索P[0]
    2. Q[i] 找到匹配项后,将P[1]Q[i-1]Q[i+1] 进行比较(使用适当的包装)。
    3. 如果两者都不匹配,则返回 1 并继续在 Q 中搜索 P[0],从 Q[i+1] 开始。
    4. 在第 2 步中找到匹配项后,继续进行比较,向前通过 P 并在同一方向通过 Q。要么会发现不匹配,在这种情况下多边形不同,您可以立即停止(无需继续搜索 P[0] 的另一个匹配项),或者您将一直遍历,它们是相同的。

    顺便说一句,如果您想使用一种算法,该算法需要识别轮廓中的字典最小顶点,但顶点可能重复,您可以通过考虑最小相邻顶点或顺时针(或逆时针- 顺时针,只要你是一致的)相邻顶点。同样,这取决于不重复的边。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-10
      • 1970-01-01
      • 2021-10-21
      • 2012-04-09
      • 2018-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多