给定最大10 000个自然和不同数字的向量,找到4个数字(a,b,c,d),使a + b + c = d

时间:2010-06-04 10:52:36

标签: algorithm math

我通过遵循直接但非最佳算法解决了这个问题。我按降序对矢量进行了排序,之后从max到min减去了数字,看是否得到a + b + c = d。 请注意,我没有在任何地方使用过这样一个事实:元素是自然的,不同的,最多只有10000个。我想这些细节是关键。 这里有没有人提示解决这个问题的最佳方法?

提前谢谢你!

后来编辑: 我的想法是这样的:

'<<quicksort in descending order>>'

for i:=0 to count { // after sorting, loop through the array
    int d := v[i];
    for j:=i+1 to count {
        int dif1 := d - v[j];
        int a := v[j];

       for k:=j+1 to count {
           if (v[k] > dif1)
              continue;
           int dif2 := dif1 - v[k];
         b := v[k];

    for l:=k+1 to count {
 if (dif2 = v[l]) {
    c := dif2; 
     return {a, b, c, d}
 }
           }
        }
    }
}

你怎么看?(对不好的缩进感到抱歉)

3 个答案:

答案 0 :(得分:7)

O(n 2 log n)中的解:

计算所有可能的总和和差异的集合:

{a i + a j :1&lt; = i,j&lt; = n}

{a i -a j :1&lt; = i,j&lt; = n}

(将它们存储在平衡的二叉搜索树中)并检查它们是否具有公共元素。如果是,则有i,j,k,l使得 i + a j = a k - a l < / sub>,即 i + a j + a l = a k

O中的解(a n log a n ),其中 n 是向量中的最大数字:

计算多项式

(x a 1 + x a 2 + ... + x a <子>名词 3

你可以在O(a n log a n )中使用Fast Fourier Transform(第一个计算平方,然后是第三个幂;请参阅{{3}为了描述)。观察到乘法后,系数x b i 由乘法x a i * x a形成 j * x a k = x a i + a j某些i,j,k的 + a k 。检查结果多项式中是否存在幂x a l

不幸的是,这允许一些i,j,k被使用两次。减去3(x 2a 1 + ... + x 2a n )*(x a 1 + ... + x a n ) - 2(x 3a 1 + ... + x 3a n )将删除那些x a i + a j +一<子>ķ

答案 1 :(得分:4)

Shamir和Schroeppel的算法在时间O(N ^ 2)和存储器O(N)中解决了这个问题,当N是输入的数量时。它基本上是sdcvvc提出的,但不是存储集合{a i + a j }作为一个整体,而是重复计算适当间隔的总和。这样可以节省内存,但不会增加时间复杂度。

Richard Schroeppel,Adi Shamir:“T = O(2 ^(n / 2)),S = O(2 ^(n / 4))算法的某些NP完全问题”。 SIAM J. Comput。 10(3):456-464(1981)

答案 2 :(得分:1)

这是用Python实现的@MicSim's comment to @sdcvvc's answer

def abcd(nums):
    sums = dict((a+b, (a,b)) for a, b in combinations(nums, 2))

    for c, d in combinations(sorted(nums), 2): # c < d
        if (d-c) in sums:
            a, b = sums[d-c]
            assert (a+b+c) == d
            if a == c or b == c: continue # all a,b,c,d must be different
            a,b,c = sorted((a,b,c))
            assert a < b < c < d
            return a,b,c,d

combinations()可以是itertools.combinations()

def combinations(arr, r):
    assert r == 2 # generate all unordered pairs
    for i, v in enumerate(arr):
        for j in xrange(i+1, len(arr)):
            yield v, arr[j]

时间和空间是O(N 2 )。

示例:

>>> abcd(range(1, 10000))
(1, 2, 3, 6)