开发者

Given a vector of maximum 10 000 natural and distinct numbers, find 4 numbers(a, b, c, d) such that a + b + c = d

I solved this problem by following a straightforward but not opti开发者_开发技巧mal algorithm. I sorted the vector in descending order and after that substracted numbers from max to min to see if I get a + b + c = d. Notice that I haven't used anywhere the fact that elements are natural, distinct and 10 000 at most. I suppose these details are the key. Does anyone here have a hint over an optimal way of solving this?

Thank you in advance!

Later Edit: My idea goes like this:

'<<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}
 }
           }
        }
    }
}

What do you think?(sorry for the bad indentation)


Solution in O(n2 log n):

Compute sets of all possible sums and differences:

{ai+aj: 1 <= i,j <= n}

{ai-aj: 1 <= i,j <= n}

(store them in a balanced binary search tree) and check if they have a common element. If yes, there are i,j,k,l such that ai + aj = ak - al, that is ai+aj+al=ak.

Solution in O(an log an), where an is the largest number in the vector:

Compute the polynomial

(xa1+xa2 + ... + xan)3

you can do it in O(an log an) using Fast Fourier Transform (first compute square, then third power; see here for description). Observe that after multiplication a coefficient xbi was formed from multiplication xai * xaj * xak= xai+aj+ak for some i,j,k. Check if there is a power xal in the resulting polynomial.

Unfortunately this allows some i,j,k to be used twice. Subtracting 3(x2a1+...+x2an)*(xa1+...+xan) - 2(x3a1+...+x3an) will remove those xai+aj+ak.


There is an algorithm by Shamir and Schroeppel that solves this problem in time O(N^2) and with memory O(N), when N is the number of inputs. It basically is what sdcvvc proposes, but instead of storing the sets {ai + aj} as a whole one would repeatedly compute only the sums in appropriate intervals. This saves memory, but does not increase the time complexity.

Richard Schroeppel, Adi Shamir: "A T=O(2^(n/2)), S=O(2^(n/4)) Algorithm for Certain NP-Complete Problems". SIAM J. Comput. 10(3): 456-464 (1981)


Here's @MicSim's comment to @sdcvvc's answer implemented in Python:

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

Where combinations() could be itertools.combinations() or

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]

It is O(N2) in time and space.

Example:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜