This was recently asked to a friend in an interview and we do not know of any solution other than the simple O(n3) one.
Is there some better algorithm?
The question is to find all triplets in an integer array whose sum is less than or equal to given sum S.
Note: I have seen other such problems on SO with performance O(n2log n) but all of them were solving the easier version of this problem like where arr[i] + arr[j] + arr[k] = S
or where they were only checking whether one such triplet exists.
My question is to find out all i,j,k
in arr[]
such that arr[i] + arr[j] + arr[k] <= S
I'm keeping my original answer below, but this can actually be solved in O(n). My new solution uses a Queue to keep track of the triplets. It only returns the number of triplets but you could create a list to track the triplet lists pretty easily if that is what's required.
I believe this algorithm should do the trick in O(N^2). You should sort the array beforehand though.
Essentially, I am just finding all possible triplets where the first index i is zero and the next index is j by searching through the remaining indices (k) for all sums less than or equal to x (or S in your case). After that, I increment j by 1 and repeat the process. Once j comes to the end of the array, I start the process over with my i being i + 1 now and keep going until i equals the second to last index value (since at that point there are no possible triplets left).
Python code
This can be solved in O(n^2) complexity.
First sort the numbers --> O(nlog(n))
Now starting from the front, fix one number at a time. Now problem reduces to find 2 numbers in sorted array whose sum is <= given sum. Using 2 pointers, one from start and one from end, this can be solved in O(n). So overall complexity is O(n2)
I have an idea, but I'm not sure if it works.
Preprocess (remove elements >
S
) and sort the array first.Then, after you picking up
arr[i]
andarr[j]
wherei < j
, you may binary searchS - arr[i] - arr[j]
in the remainingarray[j+1...n]
. Once you binary-searched the indexm
, thek
could lie betweenj+1
andm
.I think this may reduce the complexity. What do you think?
From a worst-case asymptotic perspective, there is no better algorithm since the size of the output is potentially
O(n^3)
.e.g. Let the array be the numbers 1 through
n
. LetS = 3n
. Clearly, any subset of three array elements will be less thanS
and there are(n choose 3) = O(n^3)
subsets.There are a few ways you can speed up non-worst cases though. For example, try sorting the array first. That should give you some hints.
What would be the complexity of this?
If applied to a sorted list (ascending),
f
simply lists the triplets who's sum is less than or equal tos
, one by one, without creating duplicates or scanning past the first element that is too big.Haskell code:
Output: