You'd only get a O(n^2) solution if you nested your loops. Multiple sequential loops of O(n) (so the next loop running once the preceding loop has completed) add up to a O(n) final solution, you can use as many of those as you need.
If your input doesn't include start and end numbers and you only know that they are going to be a sequence of positive integers with one number somewhere in the middle missing, the solution would be to first count the numbers and record the minimum and maximum number. Then loop from minimum to maximum, and include any number that is either missing or has a count of 2. Count using a dictionary, that way you'll also know what numbers are missing:
def missing_or_doubled(inputlist):
counts = {}
for n in inputlist: # O(n) loop
counts[n] = counts.get(n, 0) + 1
start, end = min(counts), max(counts) # two sequential O(n) loops
# final O(n) loop to find missing number and number that appears twice
return [i for i in range(start, end + 1) if counts.get(i) in {2, None}]
That's 4 different O(n) loops, all sequential. You can determine start
and end
inside the for n in inputlist
loop too, but that's going to be slower; the min()
and max()
functions are implemented in C and their lower constant cost will beat any attempt implemented in pure Python.
Demo:
>>> missing_or_doubled([3, 1, 2, 5, 3])
[3, 4]
>>> missing_or_doubled([14, 19, 17, 13, 12, 10, 16, 17, 18, 22, 11, 15, 20])
[17, 21]
If you do know the start or end number up front (either because it is passed to your code as a parameter, or the problem description explicitly states what the start or end number will be), then just replace either the min(counts)
or max(counts)
assignments with that information. For example, if the starting number is always supposed to be 1
, just use range(1, end + 1)
.