我正在寻找快速算法:
我有一个大小为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))
请分享您对此问题的想法,谢谢
答案 0 :(得分:8)
修改:以下答案适用于此问题的一个版本,在该版本中您只需要一个加起来的三元组。当你想要所有这些时,因为可能至少有O(n ^ 2)个可能的输出(如ex0du5所指出的),甚至在重复元素的病理情况下也是O(n ^ 3),你不是将基于散列(从值映射到具有该值的索引列表)击败简单的O(n ^ 2)算法。
这基本上是the 3SUM problem。如果没有可能无限大的元素,最着名的算法大约是O(n^2)
,但我们只能证明它对于大多数计算模型来说不会比O(n lg n)
快。
如果整数元素位于[u, v]
范围内,则可以使用FFT在O(n + (v-u) lg (v-u))
中对此进行略微不同的版本。我将描述一个将此问题转换为该问题的过程,在那里解决,然后根据此转换找出问题的答案。
我知道如何用FFT解决的问题是在数组中找到长度为3的算术序列:即序列a
,b
,c
和{ {1}},或等效地c - b = b - a
。
不幸的是,转型的最后一步并不像我想的那么快,但是当我们到达那里时我会谈到这一点。
让我们调用原始数组a + c = 2b
,其中包含整数X
。我们希望找到x_1, ..., x_n
,i
,j
这样的k
索引。
在x_i + x_j = x_k
时间内找到u
的最低v
和最高X
。让O(n)
为u'
,min(u, u*2)
为v'
。
构造长度为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
)。
将2X
视为多项式X
的表示,其中度Z
项的系数为p
。如果i
为Z[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 answer在Z
时间内找到 p 2 ,Z
为O(|Z| log |Z|)
}。我们得出另一个系数数组;称之为|Z|
。
循环遍历v' - u' + 1
中的每个W
。 (回想一下,我们所需的均匀间隔都位于x_k
的元素上,而不是X
。)如果相应的X
为此元素的两倍,即2*X
,是1,我们知道它不是任何重要进展的中心,我们可以跳过它。 (如前所述,它应该只是一个正整数。)
否则,它可能是我们想要的进展的中心(因此我们需要找到W
和W[2*(x_k - u')]
)。但是,不幸的是,它也可能是一个没有我们想要的形式的进展的中心。所以我们需要检查一下。循环遍历i
的其他元素j
,并检查x_i
,X
,2*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
并且一切都会很好。
我认为可以使用一个稍微不同的多项式来做到这一点,但我还没有实际工作。我会再考虑一下......
部分基于{{3}}。
答案 1 :(得分:1)
必须至少为O(n ^ 2),因为有n(n-1)/ 2个不同的总和可以检查其他成员。你必须计算所有这些,因为任何总和可以是任何其他成员(从一个例子开始并置换所有元素以说服自己必须检查所有元素)。或者看看斐波那契的具体事情。
因此计算并在哈希表中查找成员会产生摊销的O(n ^ 2)。如果您需要最坏的情况,请使用有序树。
答案 2 :(得分:1)
你基本上需要找到所有不同的值对总和,所以我认为你不会比O(n 2 )更好。但您可以通过对列表进行排序并减少重复值进行优化,然后仅将值与任何等于或大于的值配对,并在总和超过列表中的最大值时停止。