@KlimentMerzlyakov's solution improves the average time complexity from O(n ^ 2) to O(n) at the cost of space having to store all the numbers in a set.
You can improve the space overhead while keeping the time complexity at O(n) by storing each positive integer as a set bit in a binary number instead. Then invert the number so the lowest set bit would be at the the smallest positive integer. You can get the lowest set bit with the algorithm from this answer.
As @Ry- pointed out in the comment, however, since integers are immutable in Python and have to be copied for each operation, storing the bits as an integer would result in a time complexity of O(n ^ 2). Instead, you can store the bits in a bytearray to perform operations in-place, and then iteratively find the index of the lowest byte with an unset bit to calculate the position of the lowest unset bit, so that each additional number would only cost 1 bit of space overhead while the overall time complexity remains at O(n):
def solution(A):
size = len(A)
b = bytearray((size >> 3) + 1)
for i in A:
if 0 < i <= size:
i -= 1
b[i >> 3] |= 1 << (i & 7)
for i, byte in enumerate(b):
if byte != 255:
break
byte = ~byte
return (i << 3) + (byte & -byte).bit_length()
so that:
for arr in (
list(range(1000)) + list(range(1001, 2000)),
[8, 2, 1, 4, 3, 5],
[-3, 1, 1, -7, 5, 3],
[-11, -1, 3]
):
print(solution(arr))
outputs:
1000
6
2
1
Demo here