考虑有三个相同长度的数组列表,其中包含正数,负数和零。我不得不写一个程序来找到总和为零的组合。所以基本上,如果数组是: -
A = {0, -1, 2}
B = {0, -1, -2}
C = {0, -2, 0}
O / P:A [0] + B [0] + C [0],A [2] + B [2] + C [2]等。
我可以想到两种方式, 1.如果零打印索引,则有3个for循环并使用[i] + b [j] + c [k]计算总和。 大O将是O(N ^ 3) 2.有两个for循环,但使用二进制搜索找到第三个元素,它将总和为零。 大O将是O(N ^ 2LogN)
还有其他方法吗?
感谢。
修改 根据下面给出的答案,我的第一次解决是最快的。但如果问题是“找到”组合的数量并且不打印它们,那么请参阅下面的Grigor Gevorgyan答案。
答案 0 :(得分:3)
可以使用 2指针方法在 O(n ^ 2) 中完成。
对数组进行排序。现在做以下事项:
设置 ans = 0 。
使用索引 i 的阵列 a 运行外部循环。现在设置 j = 0,k = n - 1
查看 sum = a [i] + b [j] + c [k] 。
如果 sum< 0 ,增加 j
如果 sum> 0 减少 k
如果 sum == 0 ,请找到等于 b [j] 和 <的元素范围em> c [k] 并将范围长度产品添加到答案中。然后将 j 和 k 设置为该范围之外的第一个元素。
这是有效的,因为数组是排序的,加法是线性函数
内部部分以 O(n)运行,整体 O(n ^ 2)复杂。
C ++中的示例代码:
sort( a, a + n );
sort( b, b + n );
sort( c, c + n );
ans = 0;
for( i = 0; i < n; ++i )
{
j = 0, k = n - 1;
while( j < n && k > 0 )
{
sum = a[ i ] + b[ j ] + c[ k ];
if( sum < 0 ) ++j;
else if( sum > 0 ) --k;
else
{
// find the equal range
for( jj = j; jj < n && b[ jj ] == b[ j ]; ++jj );
for( kk = k; kk >= 0 && c[ kk ] == c[ k ]; --kk );
// add pairs quantity from these ranges
ans += ( jj - j ) * ( k - kk );
j = jj, k = kk;
}
}
注意 :不需要对数组 a 进行排序,只是看起来不错:)< / p>
答案 1 :(得分:2)
我认为这是3SUM:
http://en.wikipedia.org/wiki/3SUM
引用维基百科的文章:
有一个简单的算法可以在O(n2)时间内解决3SUM,首先对数组中的每个元素进行散列,找到所有可能的对,然后最后检查是否存在剩余值(这只是总和的负数)每一对)使用哈希表。
答案 2 :(得分:1)
天真的方法是检查所有子集,但运行时间很差。 http://mathworld.wolfram.com/k-Subset.html 没有进一步的限制,我相信这是NP完全子集求和问题。有一个与背包问题相关的解决方案可以提供一个不错的解决方案。 http://en.wikipedia.org/wiki/Subset_sum_problem
您是否需要找到总和为0或仅为一个的所有组合或仅包含3个元素的解?
解决方案应为{{A [0]},{B [0]},{C [0]},{C [2]},{A [0],B [0]},{A [ 0],B [0],C [0]},{A [0],B [0],C [0],C [2]},{A [1],B [1],A [2 ]},{A [2],B [2]}等等}
答案 3 :(得分:1)
此解决方案只有在您将数据读取到某些存储的数组列表中时才会加速,例如文件或任何输入流自己。用hashtable
替换第三个数组列表可以让您有一个恒定的时间来查找零和的第三个组成部分。在您的两个嵌套循环中,每次获取新对a[i]+b[j]
时,您都会在c[n0]=-a[i]+b[j]
的哈希表中查找O(1)
。因此总时间复杂度为O(n ^ 2)。让我澄清一下,这个解决方案只有在你被允许掌握阅读过程时才有帮助,如果你已经给出了数组列表,那么这个解决方案不会加速。