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?
Yep; we can solve this in O(n2) time! First, consider that your problem
Pcan 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'fromPby 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, andkat various points in the array.istarts off at the beginning and slowly works its way to the end.kpoints to the very last element.jpoints to whereihas started at. We iteratively try to sum the elements at their respective indices, and each time one of the following happens:jcloser to the end to select the next biggest number.kcloser to the beginning to select the next smallest number.For each
i, the pointers ofjandkwill 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 nextiand 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).