【问题标题】:How to quickly find sum of all pairs of elements in 2 different arrays如何快速找到2个不同数组中所有元素对的总和
【发布时间】:2017-07-14 03:50:45
【问题描述】:

所以最近我遇到了这个编程问题,我似乎无法降低复杂性(我当前的代码在 O(n^2) 中运行)。

基本上,我有四个不同的整数列表(我正在使用 python btw),包括正数和负数,比如列表 A、B、C、D。现在,这些列表中的每一个都有 1000 个整数,并且这些整数范围从 -25000 到 25000(含)。现在,假设我们从这些列表中的每一个中选择一个整数,比如 a、b、c、d。我想要找到这些 a、b、c、d 的最快方法,使得 a+b=-(c+d)。

目前,我的方法依赖于迭代 a、b 和 c、d 的每个可能的组合,然后尝试查找集合 (a+b) 中的元素是否存在于集合 -(c+d )。这当然是不切实际的,因为它在 O(n^2) 时间内运行,考虑到大列表大小 (1000) 更是如此。

因此我想知道是否有人能想到一种更有效的方法(最好是 O(n log n) 或更小),如果可能的话,用 python 编码。

抱歉,如果它相当混乱。如果您有任何问题,请告诉我,我会尽力提供更多澄清。

编辑:

这个问题是一个更大问题的一部分。更大的问题是,如果我们有 4 个数字序列,每个序列最多有 1000 个整数,比如 A、B、C、D,找到一个 a、b、c、d 使得 a+b+c+d=0。

我问了上面的问题,因为 a+b+c+d=0 意味着 a+b=-(c+d),我认为这会导致解决问题的最快方法。如果有人能想到更快的方法,请与我分享。

提前致谢! :)

【问题讨论】:

  • 您是否正在寻找适用于该条件的所有组合?
  • 是的,就是这样。可以保证至少会有 1 个这样的组合。
  • 在最坏的情况下,当 C = -A 且 D = -B 时,您将有 Θ(n^2) 解,因此您的算法至少需要 n^2 步才能产生输出。
  • 嗯,如果是这样的话,那么这个解决更大问题的算法可能是错误的......我会去提供更多的上下文。
  • 您可以尝试的一件事是对列表进行排序并使用该标准搜索其他两个数组中的元素。这可能会帮助您获得 O(nlogn) 解决方案。

标签: python arrays algorithm big-o


【解决方案1】:

你有四个数组,你想从每个数组中选择一个数字,这样四个数字的总和为零。这个问题的技术名称是 4SUM×4。

这个问题至少和3SUM×3 一样难,其中三个和为零的数字必须从三个数组中选择。通过简单地添加一个零数组,可以将 3SUM×3 的实例转换为 4SUM×4 的实例。因此,任何解决您问题的算法都可以在相同的时间复杂度下解决 3SUM×3。

似乎无法确定 3SUM×3 并不比更著名的 3SUM 问题更容易,但它似乎很可能同样困难。 3SUM×3算法可用于解决3SUM问题或determine with arbitrarily high probability无解。 (将 3SUM 减少到 3SUM×3 的唯一问题是 3SUM×3 允许像 1, 1, -2 这样的解决方案,而 3SUM 则不允许。)理论上最知名的 3SUM 算法仅胜过 O(n2 ) 乘以 (log n) 的某个幂。

鉴于所有这些,您的问题似乎不太可能在显着小于 O(n2) 的时间内渐近地解决。

【讨论】:

    【解决方案2】:

    您的问题不在于组合元素对是 O(n^2),而是您将两个这样的过程天真地组合以最终得到 O(n^4) 算法。我将假设您只需要找到 >= 1 种方法来加起来为 0 - 如果需要,我下面给出的方法可以很容易地扩展到找到 所有 种方法。

    鉴于您接受的值范围相对较窄(-25k 到 +25k,我们分别称它们为 MIN 和 MAX),您可以这样做:

    创建 2 个大小为 (MAX - MIN + 1)、“indicesA”和“indicesB”的 int 数组。这甚至还不到 0.5 MB 的内存,因此在现代系统上无需担心。

    现在循环列表 A 和 B 的所有元素,就像你之前做的那样。做类似这样的伪代码(对python不太熟悉,所以我不确定它是否按原样有效):

    for idxA, valA in enumerate(A):
        for idxB, valB in enumerate(B):
            indicesA[valA + valB - MIN] = idxA + 1
            indicesB[valA + valB - MIN] = idxB + 1
    

    现在只需在 B 和 C 上循环时将其用作 O(1) 查找表:

    for valC in C:
        for valD in D:
            neededVal = -(valC + valD) - MIN
            if indicesA[neededVal] > 0:
                print('Found solution: {0} {1} {2} {3}'.format(A[indicesA[neededVal] - 1], 
                     B[indicesB[neededVal] - 1], valC, valD))
    
    • 使用 0 初始化查找表:O(MAX - MIN)(~50k,在这种情况下小于 n^2)
    • 通过在 A 和 B 上循环填充查找表:O(n^2)
    • 在 C 和 D 上循环并检查任何解决方案:O(n^2)

    总体而言,O(n^2 + (MAX - MIN)) =~ O(n^2) 与给定的值。可能没有比这更好的了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-06
      • 2013-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多