给定3个排序的阵列A,B,C和数字S,找到i,j,k,使得A [i] + B [j] + C [k] = S

时间:2014-10-17 12:49:56

标签: arrays algorithm

我刚刚发现如何在O(n^2 log n)时间内解决这个问题(假设每个数组的长度相同):

for each A[i]:
  for each B[j]:
    if A[i] + B[j] + C.binarySearch(S - A[i] - B[j]) == S:
       return (i, j, k)

有没有办法在O(n^2)时间内解决这个问题或改进上述算法?

4 个答案:

答案 0 :(得分:0)

你拥有的算法也不错。相对于n^2log(n)增长得如此之慢,以至于它实际上可以被视为常数。例如,n = 1000000n^2 = 1000000000000log(n) = 20。一旦n变得足够大以使log(n)产生任何重大影响,n^2已经非常大,无论如何都无法计算结果。

一个灵感来自@YvesDaoust的解决方案,虽然我不确定它是否完全相同:

  • 对于每个A[i],计算余额R = S - A[i],该余数应为某些B[j]C[k]的组合;
  • 允许j = 0k = |C|-1C中的最后一个索引);
  • 如果B[j] + C[k] < R,请增加j;
  • 如果B[j] + C[k] > R,请减少k;
  • 重复上述两个步骤,直至B[j] + C[k] = Rj >= |B|k < 0

我建议不要使用微优化过多地使算法复杂化。对于任何相当小的数字组合,它将足够快。如果阵列对于这种方法而言变得太大,那么你的问题就会成为Hill Climbing等机器学习方法的理想选择。

答案 1 :(得分:0)

O(N²)解决方案非常简单。

首先考虑两个数组的情况,找到A[i] + B[j] = S'

这可以改写为A[i] = S' - B[j] = B'[j]:您需要在两个排序的数组中找到相等的值。这可以通过合并过程在线性时间内完成。 (您可以显式计算数组B',但这是不必要的,只需动态执行:而不是获取B'[j],获取S' - B[NB-1-j])。

建立此程序后,只需将C的所有元素用于搜索S - C[k]即可。

这是执行该操作的Python代码并报告所有解决方案。 (它已被重写为紧凑和对称。)

for k in range(NC):
    # Find S - C[k] in top-to-tail merged A and B
    i, j= 0, NB - 1
    while i < NA and 0 <= j:
        if A[i] + B[j] + C[k] < S:
            # Move forward A
            i+= 1
        elif A[i] + B[j] + C[k] > S:
            # Move back B
            j-= 1
        else:
            # Found
            print A[i] + B[j] + C[k], "=", A[i], "+", B[j], "+", C[k]
            i+= 1; j-= 1

执行

A= [1, 2, 3, 4, 5, 6, 7]; NA= len(A)
B= [2, 3, 5, 7, 11]; NB= len(B)
C= [1, 1, 2, 3, 5, 7]; NC= len(C)

S= 15

给出

15 = 3 + 11 + 1
15 = 7 + 7 + 1
15 = 3 + 11 + 1
15 = 7 + 7 + 1
15 = 2 + 11 + 2
15 = 6 + 7 + 2
15 = 1 + 11 + 3
15 = 5 + 7 + 3
15 = 7 + 5 + 3
15 = 3 + 7 + 5
15 = 5 + 5 + 5
15 = 7 + 3 + 5
15 = 1 + 7 + 7
15 = 3 + 5 + 7
15 = 5 + 3 + 7
15 = 6 + 2 + 7

答案 2 :(得分:0)

如果阵列是非负数的话  *您可以将所有3个数组修剪为S =&gt; A[n] > S
 *类似地,如果A [aIdx] + B [bIdx]&gt;不打扰检查阵列C.小号

答案 3 :(得分:0)

制备

  • 对每个数组进行升序+O(N.log(n))
  • 在每个数组?O(log(N))
  • 上实施二进制搜索

计算:

i=bin_search(smallest i that A[i]+B[0]+C[0]>=S); for (;i<Na;i++) { if (A[i]+B[0]+C[0]>S) break;
 j=bin_search(smallest j that A[i]+B[j]+C[0]>=S); for (;j<Nb;j++) { if (A[i]+B[j]+C[0]>S) break;
  ss=S-A[i]-B[j];
  if (ss<0) break;
  k=bin_search(ss);
  if (k found) return; // found solution is: i,j,k
  }
 }

如果我看对了,请N=max(Na,Nb,Nc)M=max(valid intervals A,B,C) ... M<=N

  • (3*N.log(N)+log(N)+M*log(N)*M*log(N)) -> O((M^2)*log(N))
  • j二元搜索只能调用一次,然后在需要时迭代+1
  • 复杂性相同但N已更改
  • 对于平均条件来说要快得多,因为M<<N