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?
Reduction : I think @John Feminella solution O(n2) is most elegant. We can still reduce the A[n] in which to search for tuple. By observing A[k] such that all elements would be in A[0] - A[k], when our search array is huge and SUM (s) really small.
A[0] is minimum :- Ascending sorted array.
s = 2A[0] + A[k] : Given s and A[] we can find A[k] using binary search in log(n) time.
How about something like this, which is O(n^2)
This finds if sum of 3 elements is exactly equal to your number. If you want closest, you can modify it to remember the smallest delta(difference between your number of current triplet) and at the end print the triplet corresponding to smallest delta.
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":Notice that you can go from this version of the problem
P'
fromP
by subtracting your S/3 from each element inA
, 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:
This algorithm works by placing three pointers,
i
,j
, andk
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 wherei
has started at. We iteratively try to sum the elements at their respective indices, and each time one of the following happens:j
closer to the end to select the next biggest number.k
closer to the beginning to select the next smallest number.For each
i
, the pointers ofj
andk
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 thati
, since we'd be summing the same elements, just in a different order. After that point, we try the nexti
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).
Note that we have a sorted array. This solution is similar to John's solution only that it looks for the sum and does not repeat the same element.
certainly this is a better solution because it's easier to read and therefore less prone to errors. The only problem is, we need to add a few lines of code to avoid multiple selection of one element.
Another O(n^2) solution (by using a hashset).
The problem can be solved in O(n^2) by extending the 2-sum problem with minor modifications.A is the vector containing elements and B is the required sum.
int Solution::threeSumClosest(vector &A, int B) {