发现三个元素中的阵列,其总和最接近于给定数目阵列、总和、数目、最接近

2023-09-10 22:26:41 作者:青狂不轻狂!

由于整数数组,A 1 ,A 2 ,...,A N ,包括正片和负片,而另一整数S.现在我们需要找到阵列,其总和最接近给定整S.如果存在一个以上的溶液在三个不同的整数,它们中的任何是确定

您可以假定所有的整数都int32_t范围之内,并没有算术溢出会发生计算的总和。 S是没什么特别的,但一个随机选择号码。

有没有什么有效的算法比蛮力搜索等找到三个整数?

解决方案   

有没有什么有效的算法比蛮力搜索等找到三个整数?

是的;我们可以在O(N 2 )的时间解决这个问题!首先,考虑您的问题 P 可以在这省去了一个目标值方式略有不同等价表述:

  

原题 P :由于数组 A N 整数和目标值取值,确实存在一个三元组由 A 求和,以取值

     

修改问题 P':给定一个数组 A 的 N 整数,不存在从 A 存在一个三元组的总和为零?

注意,你可以从这个版本的问题 P'的 P 减去您的S / 3从 A 每一个元素,但现在你不再需要的目标值。

显然,如果我们简单地测试所有可能的3元组,我们会解决在澳的问题(N 3 ) - 这就是蛮力基线。是否有可能做的更好?如果我们选择的元组在一个有点聪明的办法吗?

首先,我们投资一些时间到阵列,其中成本我们邻初始处罚(N log n)的排序。现在我们执行这个算法:

 的(我在1..N-2){
  J = I + 1 //之后我开始。
  K =ñ//开始在数组的末尾。

  而(K> = j)条{
    //我们得到了一个匹配!全做完了。
    如果(A [I] + A [J] + A [K] == 0)收益率(A [1],A [J],A [K])

    //我们不匹配。让我们试着让靠近一点:
    //如果金额过大,递减ķ。
    //如果金额过小,增加学家
    (A [I] + A [J] + A [K] 0)? K--:J ++
  }
  //当while循环结束,J和K已通过彼此有
  //没有更多有用的组合,我们可以用这个,我试试。
}
 

该算法的工作原理是将三分,Ĵ K 在阵列中的各个点。 开头开始了,慢慢地工作它的方式来结束。 K 点到最后的元素。 Ĵ点,其中,已开始在。我们反复尝试总结的元素在各自的指数,每一次发生下列情况之一:

的总和是完全正确的!我们已经找到了答案。 在该款项是太小了。移动Ĵ更接近最终选择未来最大数量。 的总和太大。移动 K 接近开始选择下一个最小号。

对于每个Ĵ K 将逐渐接近对方。他们最终会互相传球,而在这一点上,我们不需要去尝试任何其他为,因为我们会进行总结相同的元素,只是在一个不同的顺序。在这之后,我们尝试下和重复。

最后,我们无论是穷尽有用的功能,否则我们会找到解决办法。你可以看到,这是O(n 2 ),因为我们执行外环O(N)次,我们执行内环O(N)次。这是可能做到这一点子二次如果你真的看中了,通过重新presenting每个整数位矢量,并进行快速傅立叶变换,但是这超出了这个答案的范围。

这12个Excel函数,据说是财务职场老鸟的必备技

注意:由于这是一个面试问题,我已经被骗了一点点在这里:这种算法允许同一元素多次的选择。即,(-1,-1,2)将是一个有效的解决方案,如将(0,0,0)。它也发现只有确切的答案,而最接近的答案,作为标题提及。作为一个练习的读者,我会让你知道如何使它只不同元素的工作(但它是一个非常简单的变化),并准确的回答(这也是一个简单的变化)。

Given an array of integers, A1, A2, ..., An, including negatives and positives, and another integer S. Now we need to find three different integers in the array, whose sum is closest to the given integer S. If there exists more than one solution, any of them is ok.

You can assume all the integers are within int32_t range, and no arithmetic overflow will occur with calculating the sum. S is nothing special but a randomly picked number.

Is there any efficient algorithm other than brute force search to find the three integers?

解决方案

Is there any efficient algorithm other than brute force search to find the three integers?

Yep; we can solve this in O(n2) time! First, consider that your problem P can be phrased equivalently in a slightly different way that eliminates the need for a "target value":

original problem P: Given an array A of n integers and a target value S, does there exist a 3-tuple from A that sums to S?

modified problem P': Given an array A of n integers, does there exist a 3-tuple from A that sums to zero?

Notice that you can go from this version of the problem P' from P by subtracting your S/3 from each element in A, but now you don't need the target value anymore.

Clearly, if we simply test all possible 3-tuples, we'd solve the problem in O(n3) -- that's the brute-force baseline. Is it possible to do better? What if we pick the tuples in a somewhat smarter way?

First, we invest some time to sort the array, which costs us an initial penalty of O(n log n). Now we execute this algorithm:

for (i in 1..n-2) {
  j = i+1  // Start right after i.
  k = n    // Start at the end of the array.

  while (k >= j) {
    // We got a match! All done.
    if (A[i] + A[j] + A[k] == 0) return (A[i], A[j], A[k])

    // We didn't match. Let's try to get a little closer:
    //   If the sum was too big, decrement k.
    //   If the sum was too small, increment j.
    (A[i] + A[j] + A[k] > 0) ? k-- : j++
  }
  // When the while-loop finishes, j and k have passed each other and there's
  // no more useful combinations that we can try with this i.
}

This algorithm works by placing three pointers, i, j, and k at various points in the array. i starts off at the beginning and slowly works its way to the end. k points to the very last element. j points to where i has started at. We iteratively try to sum the elements at their respective indices, and each time one of the following happens:

The sum is exactly right! We've found the answer. The sum was too small. Move j closer to the end to select the next biggest number. The sum was too big. Move k closer to the beginning to select the next smallest number.

For each i, the pointers of j and k will gradually get closer to each other. Eventually they will pass each other, and at that point we don't need to try anything else for that i, since we'd be summing the same elements, just in a different order. After that point, we try the next i and repeat.

Eventually, we'll either exhaust the useful possibilities, or we'll find the solution. You can see that this is O(n2) since we execute the outer loop O(n) times and we execute the inner loop O(n) times. It's possible to do this sub-quadratically if you get really fancy, by representing each integer as a bit vector and performing a fast Fourier transform, but that's beyond the scope of this answer.

Note: Because this is an interview question, I've cheated a little bit here: this algorithm allows the selection of the same element multiple times. That is, (-1, -1, 2) would be a valid solution, as would (0, 0, 0). It also finds only the exact answers, not the closest answer, as the title mentions. As an exercise to the reader, I'll let you figure out how to make it work with distinct elements only (but it's a very simple change) and exact answers (which is also a simple change).