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?
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.
class Queue (object):
def __init__ (self):
self.queue = []
self.itemCount = 0
def enqueue (self, item):
self.queue.append (item)
self.itemCount += 1
def dequeue (self):
self.itemCount += 1
return (self.queue.pop(0))
def findAllTriplets(li,S):
if len(li) < 3:
return "Not enough elements for triplets"
tQ = Queue() # Queue to keep track of data
tripletNum = 0 # Integer to track number of triplets to be returned
tripletSum = 0 # Value of sum of consecutive list items for tripletNum evaluation
for number in li:
# Add the number to the queue immediately and add it to the current triplet sum
tQ.enqueue(number)
tripletSum += number
# For the first 3 numbers only enqueue and add to the sum
if tQ.itemCount < 3:
continue
# Afterwards, check if the sum of the latest three is less than S
else:
if(tripletSum <= S):
tripletNum += 1
# Dequeue the oldest element in the queue and subtract it from the tracked triplet sum
tripletSum -= tQ.dequeue()
return tripletNum
I believe this algorithm should do the trick in O(N2). 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
def numTriplets(a,x):
if len(a) < 3:
return None
i = 0
j = 1
triplets = []
while True:
for k in range(j+1,len(a)):
if a[i] + a[j] + a[k] <= x:
triplets.append([i,j,k])
j += 1
if j == len(a) - 1:
i += 1
j = i + 1
if i == len(a) - 2:
return triplets