二次复杂度的 4SUM 变化 (Python 3.5)

4SUM variation in quadratic complexity (Python 3.5)

我对 4SUM 问题的变体遇到了一些问题。本质上,我们需要从每个 500 个整数的 4 个元组中选择一个数字,例如 ijkl,例如 abcd,这样 i+j+k+l == 0。这些整数的范围从 -2000020000。目前,我相信我的代码的时间复杂度为 O(n3)。根据我的导师的说法,这个时间复杂度可以进一步降低到 O(n2 log n)O (n2)(通过使用哈希表或其他东西)。

不幸的是,如果这种哈希表方法是可行的方法,我不确定如何着手实施它。因此,如果有人能告诉我如何在 Python 3.5 中编写此程序,我将不胜感激。 (PS。请尽量使用尽可能少的嵌套循环,none 是最理想的)。

我在下面附上了我的代码以供参考。如果可以修改我当前的代码以降低其时间复杂度,请同时通知我。

import collections

import itertools


def selection(a, b, c, d):
    """program has 4 main parts,
        firstly, triple_sum finds possible 3sums in the list abc
        secondly, is_iterable ensures that inputs of tuple length 1 (ie. not iterable) are made iterable
        thirdly, main function determines if there exists possible a, b, c in abc that correspond to each d
        fourthly, main function checks if only 1 of the 3 integers from triple_sum exist in each array"""

    '''use sort O(n log n) to sort input array, then find possible 3sums in O(n^2)'''
    def triple_sum(a, res):
        a.sort()
        positions = collections.defaultdict(set)
        for i, n in enumerate(a):
            positions[n].add(i)
        for (i, ai), (j, aj) in itertools.combinations(enumerate(a), 2):
            n = res - ai - aj
            if positions[n].difference((i, j)):
                return n, ai, aj

    '''Ensure that all inputs are iterable'''
    def is_iterable(x):
        if isinstance(x, collections.Iterable):
            return x
        else:
            return x,

    a, b, c, d = is_iterable(a), is_iterable(b), is_iterable(c), is_iterable(d)
    abc = a + b + c
    abc = [i for i in abc]

    '''find value of d which has corresponding a, b, c
        and returns appropriate value if conditions are met'''
    ans_a, ans_b, ans_c, ans_d = 0, 0, 0, 0
    for i in d:
        x = 0 - i
        j = triple_sum(abc, x)
        if j[0] in a and j[1] in b and j[2] in c:
            ans_a, ans_b, ans_c, ans_d = j[0], j[1], j[2], i
            break
        elif j[0] in a and j[2] in b and j[1] in c:
            ans_a, ans_b, ans_c, ans_d = j[0], j[2], j[1], i
            break
        elif j[1] in a and j[0] in b and j[2] in c:
            ans_a, ans_b, ans_c, ans_d = j[1], j[0], j[2], i
            break
        elif j[1] in a and j[2] in b and j[0] in c:
            ans_a, ans_b, ans_c, ans_d = j[1], j[2], j[0], i
            break
        elif j[2] in a and j[0] in b and j[1] in c:
            ans_a, ans_b, ans_c, ans_d = j[2], j[0], j[1], i
            break
        elif j[2] in a and j[1] in b and j[0] in c:
            ans_a, ans_b, ans_c, ans_d = j[2], j[1], j[0], i
            break
        else:
            continue

    return ans_a, ans_b, ans_c, ans_d

提前致谢:)

PS。如果有人需要更多说明或信息,请告诉我。

理论

  • 遍历所有 (i,j) 对并创建一个以 i+j 为键和 (i,j) 为值的字典

  • 遍历所有 (k,l) 对并创建一个以 -(k+l) 为键和 (k,l) 为值的字典。

  • 遍历第一个字典的键,并检查第二个字典是否也有这个键。在这种情况下,sum((i,j,k,l)) 将是 0

每个描述的步骤都是 O(n²),因此整个算法将是 O(n²),其中 n 是元组的大小。

代码

a = [1, 2, 3, 4]
b = [5, 6, 7, 8]
c = [9, 10, 11, 12]
d = [13, 14, 15, -24]


def pairs_and_sums(list1, list2):
    return {(x + y): (x, y) for x in list1 for y in list2}


first_half = pairs_and_sums(a, b)
second_half = pairs_and_sums(c, d)

for i_plus_j in first_half:
    if -i_plus_j in second_half:
        i, j = first_half.get(i_plus_j)
        k, l = second_half.get(-i_plus_j)
        print("Solution found!")
        print("sum((%d,%d,%d,%d)) == 0" % (i, j, k, l))
        break
else:
    print "No solution found"

它输出:

Solution found!
sum((4,8,12,-24)) == 0