面试问题:三个阵列和O(N*N)

Key*_*lug 47 arrays algorithm

假设我们有三个长度为N的数组,它们包含任意数量的类型long.然后给出一个数字M(相同类型),我们的任务是从每个数组中选择三个数字A,BC(换句话说,A 应该从第一个数组中选择,B从第二个数组中选择,C从第三个数据中选择),以使之和A + B + C = M.

问题:我们可以选择所有三个数字并最终得到O(N 2)的时间复杂度吗?


插图:

数组是:

1) 6 5 8 3 9 2
2) 1 9 0 4 6 4
3) 7 8 1 5 4 3
Run Code Online (Sandbox Code Playgroud)

中号,我们已经给出是19.然后我们的选择是从第一个8,从第二个4和从第三个7.

cod*_*ict 150

这可以在O(1)空间和O(N 2)时间内完成.

首先让我们解决一个更简单的问题:
给定两个数组AB从每个数组中选择一个元素,使它们的总和等于给定的数字K.

对需要O(NlogN)的数组进行排序.
获取指针i,j以便i指向数组的开头Aj指向结束B.
找出总和A[i] + B[j]并与之进行比较K

  • 如果A[i] + B[j] == K我们找到了这对A[i]B[j]
  • 如果A[i] + B[j] < K,我们需要增加总和,所以增量i.
  • 如果A[i] + B[j] > K,我们需要减少总和,所以减少j.

排序后找到该对的过程需要O(N).

现在让我们来解决原始问题.我们现在有第三个阵列叫它C.

所以算法现在是:

foreach element x in C
  find a pair A[i], B[j] from A and B such that A[i] + B[j] = K - x
end for
Run Code Online (Sandbox Code Playgroud)

外循环运行N时间,并且对于每次运行,我们进行O(N)操作,使得整个算法O(N 2).

  • 关于你们彼此走"i"和"j"的部分:我似乎记得这是正确的,但你需要解释原因,因为在这个过程中没有检查一些元素对:例如,如果你增加`i`在开始时两次,然后减少`j`两次,从不检查对``(initial_i + 1,initial_j-1)`.一种(足够但不必要的)方式是证明任何跳过的元素对不可能总和为"K". (5认同)
  • 大!我打赌排序是重点. (4认同)
  • 在第一次迭代时,如果`A [i] + B [j] <K`,则意味着我们需要增加其中一个数字但是因为`B`被排序而且`j`位于`B`的_last_元素处因此,"B"中的最大数字是唯一可能的继续方式是增加"i"以尝试下一个最大的数字. - 如果`A [i] + B [j]> K`这意味着我们需要减少其中一个数字,但是因为`A`被排序而且`i`位于`A`的_first_元素,所以产生最小值可能来自`A`的值,唯一可能的继续方法是递减`j`以尝试下一个最小的数字. - 续 有感应. (4认同)
  • 我正在-1直到显示该部分算法的正确性.(正如我所说,我相信它*是正确的,但我希望看到它被证明!) (4认同)
  • 优秀的理由和解释的答案.:) (2认同)

Nik*_*bak 13

您可以将它减少到两个数组的类似问题,这有点着名并且具有简单的O(n)解决方案(涉及从两端迭代).

  1. 排序所有数组.
  2. 尝试A从第一个数组中的每个数字.
  3. 发现如果最后两个数组可以给我们的数字BC,这样B + C = M - A.

步骤2和3乘以给出O(n ^ 2)复杂度.

  • 无需对第一个阵列进行排序,否则完美的解决方案. (2认同)

MAK*_*MAK 9

其他解决方案已经更好了,但无论如何这里是我的O(n ^ 2)时间和O(n)内存解决方案.

将数组C的所有元素插入哈希表.(时间复杂度O(n),空间O(n))取所有对(a,b),a来自A和b来自B(时间复杂度O(n ^ 2)).对于每对,检查hastable中是否存在M-(a + b)(每个查询预期的复杂度O(1)).

因此,总体时间复杂度为O(n ^ 2),并且哈希表的空间复杂度为O(n).