【问题标题】:Calculating sum of all the distance计算所有距离的总和
【发布时间】:2015-09-09 02:32:19
【问题描述】:

我在一条直线上得到了 n 个点及其位置。我需要对每对点之间的距离求和。是否可以处理复杂度 O(n)。

示例:给定三个点,其坐标为 a(-1)、b(-3)、c(3)。 所需金额: |-1 + 3| + | - 1 - 3| + |-3 - 3 | = 12

请帮帮我。

【问题讨论】:

    标签: algorithm dynamic-programming


    【解决方案1】:
    1. 计算每个连续片段的长度:

      for (int i=0;i<n-1;i++) len[i]=x[i+1]-x[i];
      

    请注意,这是针对已排序的点。如果不是,则在计算连续段长度之前进行排序。

    1. 计算每个分段在不同的成对距离中出现的次数:对于某些分段,成对数是 leftSidePoints*rightSidePoints。换句话说,您计算总和中每个段长度的贡献。

       for (int i=0;i<n-1;i++) contributionOfSegment[i]=len[i]*(i+1)*(n-i-1);
      

      i+1 是左侧点,n-i-1 是第 i 段的右侧点

    2. 答案是所有段的贡献之和:

       int sum=0; for (i=0;i<n-1;i++) sum+=contributionOfSegment[i];
      

    更新

    几乎O(N) 算法,也不是O(Nlog(N))(标准排序),也不是O(maxX)(计算排序)。复杂度是O(N)loglog(maxX)),或者说更简单的O(N)*number_of_bits_in_maxX5N,用于几乎线性的32 位整数。

    主要逻辑仍然如我上面所述。瓶颈点是排序 - 而O(N)*number_of_bits_in_maxX 因素是排序步骤。我们将使用Van Emde Boas tree 对数组进行排序。该树支持 findNext(x) 操作 - 在 x 之后以复杂度 O(loglogmaxX) 查找下一个元素。插入也有复杂性O(loglogmaxX)

    所以,Van Emde Boas 排序看起来像:

    1. 通过for(i=0;i&lt;n;i++) tree.insert(x[i])O(N)*number_of_bits_in_maxX 中填充树,其中x 是未排序的输入数组。
    2. 在未排序数组中的O(N) 中查找最小值
    3. sortedArray[0]=min
    4. for(int i=1;i&lt;n;i++) sortedArray[i] = tree.findNext(sortedArray[i-1])

    然后,使用我上面的逻辑,只需将数组:x 替换为 sortedArray

    请注意,VEBTree 排序仅在理论上有意义,实际上它可能具有隐藏的常数因子,对于较小的 Nlog(N) 可能比 loglog(maxX) 更好,因此,标准排序可能比树排序更快。如果 N 非常大而 maxX 只是 32 或 64 位整数,VEBTree 会很酷。

    【讨论】:

    • 我认为这个问题不需要使用 O(n) 空间,看我的回答
    • @MateuszDymczyk,为了简化解释,我故意将算法拆分为基于数组的逻辑步骤。我的循环的每一步都可以即时计算,但数组版本更容易理解)
    • 我会把它放在答案中:-)
    • “在计算顺序段长度之前排序”使得它不是 O(n)。
    • @JimMischel,我知道,但我没有说我的解决方案是线性的。但是如果log(N) 因素如此重要,提问者可能会在 O(N+maxN) 中应用计算排序(如果数字小到可以作为计算排序数组中的索引)。看起来在这种情况下,它在复杂性和逻辑上都会几乎类似于 displayName 的想法。
    【解决方案2】:

    如果点按排序顺序,这是可行的。让我们举一个简单的例子,大于 n=3,因为n*(n-1)/2(所有可能的没有重复的对,其中 (a,b) 和 (b,a) 被认为是重复的)在这种情况下也是 3 并且具有误导性:

    n = 4 // number of points
    p = [-3, -1, 1, 3] // our points
    

    我们将首先计算到第一个点p[0] 的所有距离,这是一个O(n) 操作,结果是12,因为|-3 + 1| + |-3 - 1| + |-3 - 3| = 2 + 4 + 6 = 12

    我们现在观察到,由于这些点在一条线上,并且下一个点将在第一个点的右侧,所以我们可以通过简单地从上一个点减去当前点和上一个点之间的距离来计算所有距离相应的点总和:

    12 - (k - 1) * dist = 12 - (4 - 1) * 2 = 12 - 6 = 6
    

    由于点 0 和 1 之间的距离等于 2,我们需要为每个先前计算的距离减去这个值(前一点是 k-1=3 对的一部分)。在下一次迭代中,k 将小 1:

    6 - (k - 1) * dist = 6 - (3 - 1) * 2 = 6 - 4 = 2
    

    所以最终初始总和将是O(n),然后我们将不得不做O(1) n 次得到O(n)

    这将为我们生成一个部分和数组[12,6,2,0]=20,您无需存储它,只需将其可视化即可。

    【讨论】:

      【解决方案3】:

      如果对点进行排序,我可以想办法。假设我们有n 点。我们考虑两个相邻的点PiPi+1,假设Pi和其他Point之间的距离是DiPiPi+1之间的距离是d,那么Di+1 = Di + i * d - (n - i - 1) * d,那么如果从左相邻点到所有其他点的距离已知,我们可以计算 O(1) 中一个点到所有其他点的距离。我们只需要计算第一个点,并进行相应的更新。

      等式的逻辑是,当从Pi移动到Pi+1时,从Pi+1到它左边所有点的距离都增加了d,从Pi+1到它右边的所有点都减少了d

      【讨论】:

        【解决方案4】:

        无论点是排序还是未排序,都存在线性排序时间的可能解决方案。所以,让我们从点n+1 未排序的点开始。如给定的那样,这些点沿着一条线(假设是 x 轴)并且它们只有整数 x 值。假设第一个点是 P0,最后一个点是 Pn。这意味着总点数为n+1,总点距离为n

        1. 遍历这些点以找到最小值 (minX) 和最大值 (maxX) x 值;
        2. 创建一个位数组(称为BitArray[max - min + 1]);
        3. 再次遍历点,对于遇到的每个点,设置BitArray[minX + currentX] = true
        4. 现在创建另一个int Distances[n] 数组并开始遍历BitArray 中的所有值。
          1. 第一位为真,因为它将代表点minX
          2. 找到下一个真位并设置Distances[0] = thisX - minX;
          3. 这样,将所有连续距离填充到Distances 数组中。

        到目前为止,运行时间复杂度为 O(maxX - minX),它是线性的。对于足够接近的点,这将是 O(n)。此外,我们还创建了一个数组,它告诉我们 (P0, P1) 与索引 0 之间的距离,(P1, P2) 与索引 1 之间的距离,(P2, P3) 与索引 2 之间的距离等等。

        点沿x轴的排列会是这样(虚线是x轴,每个*是一个点,dn是P(n-1)和Pn之间的距离),

        ---*----------*------*--------*---------....--------*---
           ^          ^      ^        ^                     ^
           P0  (d0)  P1 (d1) P2 (d2)  P3  (d3)  ....  d(n)  Pn
        

        现在,计算是 O(n)。只是一个简单的总结。

        总和是:

        (1 * (n - 1) * Distances[0]) +
        (2 * (n - 2) * Distances[1]) + 
        (3 * (n - 3) * Distances[2]) +
        .
        .
        .
        (1 * (n - 1) * Distances[n-1])
        

        我是如何得出这个总结的

        以 P0 为例。 P0到P1到Pn的距离之和

        = d(P0, P1)  + d(P0, P2)     + ... + d(P0, Pn)
        = d[0]       + (d[0] + d[1]) + ... + (d[0] + d[1] till d[n-1])
        = (n-1)*d[0] + (n-2)*d[1]    + ... + (n-1)*d[n-1]
        

        我们以同样的方式取 P1 并计算它从 P2 到 Pn 的距离

        然后取 P3... 直到最后只考虑 P(n-1) 和 Pn 之间的距离

        将这些距离相加,我们直接得到我上面提到的公式。


        因此,如果点已排序运行时间为 O(n)如果点未排序正在运行时间是 O(maxX - minX),仍然线性增长。

        【讨论】:

        • @n.m.: 哪里不是 O(n)?在未分类的情况下?我已经提到它不是。在排序的情况下,它显然是 O(n)。
        • 是的,抱歉,错过了。
        • @n.m.: 没问题... :)
        猜你喜欢
        • 2016-12-24
        • 1970-01-01
        • 1970-01-01
        • 2015-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-16
        相关资源
        最近更新 更多