Вдохновленный различными решениями и комментариями выше, примерно на 20% -50% быстрее в моих (упрощенных) тестах, чем в самых быстрых из них (хотя я уверен, что это может быть сделано быстрее), и в обработке всех упомянутых угловых случаев ( неположительные числа, дубликаты и пустой список):
import numpy
def firstNotPresent(l):
positive = numpy.fromiter(set(l), dtype=int) # deduplicate
positive = positive[positive > 0] # only keep positive numbers
positive.sort()
top = positive.size + 1
if top == 1: # empty list
return 1
sequence = numpy.arange(1, top)
try:
return numpy.where(sequence < positive)[0][0]
except IndexError: # no numbers are missing, top is next
return top
Идея такова: если вы перечисляете положительный, дедуплицированный, отсортированный список, начиная с единицы, то первый раз, когда индекс меньше значения списка, значение индекса отсутствует в списке и, следовательно, отсутствует наименьшее положительное число из списка.
Это и другие решения, с которыми я тестировал (от adrtam , Паритош Сингх и VPfB ), все выглядят как примерно O (n), как и ожидалось. (Я думаю, довольно очевидно, что это нижняя граница, поскольку каждый элемент в списке должен быть исследован, чтобы найти ответ.) Редактировать: если посмотреть на это еще раз, конечно, большое значение для этого подхода, по крайней мере, O (n log (n)), из-за сортировки. Просто сортировка настолько быстрая, что она выглядела линейно в целом.