在数组中求和的快速算法

时间:2012-04-24 18:38:08

标签: arrays algorithm

我正在寻找快速算法:

我有一个大小为n的int数组,目标是找到数组中的所有模式
x1, x2, x3 are different elements in the array, such that x1+x2 = x3

例如我知道有一个大小为3的int数组是[1, 2, 3]然后只有一种可能性:1 + 2 = 3(考虑1 + 2 = 2 + 1)

我正在考虑实现Pairs和Hashmaps以快速实现算法。 (我现在最快的一个仍然是O(n^2))

请分享您对此问题的想法,谢谢

3 个答案:

答案 0 :(得分:8)

修改:以下答案适用于此问题的一个版本,在该版本中您只需要一个加起来的三元组。当你想要所有这些时,因为可能至少有O(n ^ 2)个可能的输出(如ex0du5所指出的),甚至在重复元素的病理情况下也是O(n ^ 3),你不是将基于散列(从值映射到具有该值的索引列表)击败简单的O(n ^ 2)算法。


这基本上是the 3SUM problem。如果没有可能无限大的元素,最着名的算法大约是O(n^2),但我们只能证明它对于大多数计算模型来说不会比O(n lg n)快。

如果整数元素位于[u, v]范围内,则可以使用FFTO(n + (v-u) lg (v-u))中对此进行略微不同的版本。我将描述一个将此问题转换为该问题的过程,在那里解决,然后根据此转换找出问题的答案。

我知道如何用FFT解决的问题是在数组中找到长度为3的算术序列:即序列abc和{ {1}},或等效地c - b = b - a

不幸的是,转型的最后一步并不像我想的那么快,但是当我们到达那里时我会谈到这一点。


让我们调用原始数组a + c = 2b,其中包含整数X。我们希望找到x_1, ..., x_nij这样的k索引。

  1. x_i + x_j = x_k时间内找到u的最低v和最高X。让O(n)u'min(u, u*2)v'

  2. 构造长度为max(v, v*2)的二进制数组(bitstring)Z;如果v' - u' + 1或其双Z[i]包含X[x_1*2, ..., x_n*2]将为真。这是u' + i初始化;只需遍历O(n)的每个元素,并设置X的两个对应元素。

    在我们构建此数组时,我们可以将找到的任何重复项的索引保存到辅助列表Z中。完成Y后,我们只会检查Z中每个2 * x_i的{​​{1}}。如果有,我们已经完成;否则重复是无关紧要的,我们可以忘记x_i。 (唯一的情况稍微复杂一点,如果重复Y;那么我们需要三个不同的副本来获得解决方案。)

    现在,问题的解决方案,即Y,将0中显示为三个均匀间隔的解决方案,因为一些简单的代数操作会给我们x_i + x_j = x_k。请注意,末尾的元素是我们特殊的双重条目(来自Z),中间的元素是常规条目(来自2*x_j - x_k = x_k - 2*x_i)。

  3. 2X视为多项式X的表示,其中度Z项的系数为p。如果iZ[i],则X[1, 2, 3, 5](因为我们有1,2,3,4,5,6和10);然后Z 1 + x + x 2 + x 3 + x 4 + x 5 < / sup> + x 9

    现在,请记住高中代数中两个多项式的乘积中 x c 的系数是所有 a,b a + b = c x a 的第一个多项式系数乘以<的第二个系数< EM> X b'/ SUP> 的。因此,如果我们考虑 q = p 2 x 2j 的系数(对于 j) 1111110001)将是p的所有 i 的总和。但由于Z[j] = 1是二进制的,因此正好是{em> i,j,k 的三元组数,它们是Z[i] * Z[2*j - i]中均匀间隔的三元组。请注意,(j,j,j)总是这样的三元组,因此我们只关心值为&gt;的元素。 1。

    然后我们可以Fast Fourier Transform使用this answerZ时间内找到 p 2 ZO(|Z| log |Z|) }。我们得出另一个系数数组;称之为|Z|

  4. 循环遍历v' - u' + 1中的每个W。 (回想一下,我们所需的均匀间隔都位于x_k的元素上,而不是X。)如果相应的X为此元素的两倍,即2*X,是1,我们知道它不是任何重要进展的中心,我们可以跳过它。 (如前所述,它应该只是一个正整数。)

    否则,它可能是我们想要的进展的中心(因此我们需要找到WW[2*(x_k - u')])。但是,不幸的是,它也可能是一个没有我们想要的形式的进展的中心。所以我们需要检查一下。循环遍历i的其他元素j,并检查x_iX2*x_i是否为x_k三倍2*x_j (通过检查j)。如果是这样,我们有答案;如果我们在没有命中的情况下通过所有Z[2*(x_k - x_j) - u'],那么FFT只能找到虚假答案,我们必须检查X的另一个元素。

    因此,最后一步是O(n * 1 +(x_k的数量,W [2 *(x_k - u&#39;)]> 1,实际上不是解决方案)),这可能是W,这显然不合适。应该有办法避免在输出O(n^2)中生成这些虚假答案;如果我们知道任何适当的W系数肯定有答案,那么最后一步将是W并且一切都会很好。

    我认为可以使用一个稍微不同的多项式来做到这一点,但我还没有实际工作。我会再考虑一下......

  5. 部分基于{{3}}。

答案 1 :(得分:1)

必须至少为O(n ^ 2),因为有n(n-1)/ 2个不同的总和可以检查其他成员。你必须计算所有这些,因为任何总和可以是任何其他成员(从一个例子开始并置换所有元素以说服自己必须检查所有元素)。或者看看斐波那契的具体事情。

因此计算并在哈希表中查找成员会产生摊销的O(n ^ 2)。如果您需要最坏的情况,请使用有序树。

答案 2 :(得分:1)

你基本上需要找到所有不同的值对总和,所以我认为你不会比O(n 2 )更好。但您可以通过对列表进行排序并减少重复值进行优化,然后仅将值与任何等于或大于的值配对,并在总和超过列表中的最大值时停止。