According to Python wiki: Time complexity, set is implemented as a hash table. So you can expect to lookup/insert/delete in O(1) average. Unless your hash table's load factor is too high, then you face collisions and O(n).
P.S. for some reason they claim O(n) for delete operation which looks like a mistype.
P.P.S. This is true for CPython, pypy is a different story.
Answer from Sergey Romanovsky on Stack OverflowAccording to Python wiki: Time complexity, set is implemented as a hash table. So you can expect to lookup/insert/delete in O(1) average. Unless your hash table's load factor is too high, then you face collisions and O(n).
P.S. for some reason they claim O(n) for delete operation which looks like a mistype.
P.P.S. This is true for CPython, pypy is a different story.
The other answers do not talk about 2 crucial operations on sets: Unions and intersections. In the worst case, union will take O(n+m) whereas intersection will take O(min(x,y)) provided that there are not many element in the sets with the same hash. A list of time complexities of common operations can be found here: https://wiki.python.org/moin/TimeComplexity
Time complexity of python set operations?
Lookup time in a list vs. set
Don't understand time complexity of this easy leetcode question
python - searching performance in list is better than in set - Stack Overflow
I understand that sets are data structures where all its elements are sorted and it doesn't contain any duplicate values, but why is their time complexity just O(1)?
How can it be a constant value, even if the set contains millions of elements?
I thought that the complexity was O(n*log(n)) due to a binary search, but looks like it's even faster and I can't really understand how.
Thanks in advance for any answer!
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
hashset = set()
for n in nums:
if n in hashset:
return True
hashset.add(n)
return FalseThis is the solution provided and they say its O(n). The for loop is O(n) and the "if n in hashset" is O(n) and they're nested so how isn't this O(n2)?
My original comment, which I was asked to incorporate into this answer (good idea!): Lookup time accounts for very little of what you're timing. You're mostly timing how long it takes just to do the set(range(1000000)) and list(range(1000000)) parts. Building the set/list to begin with are far more expensive than the lookup. Use the -s argument to take the setup cost out of what you're timing.
Elaborating on my comment, and since other answers didn't show the use of -s, here it is:
$ python -m timeit -n 100 -s "n = 1; c = set(range(1000000))" "n in c"
100 loops, best of 5: 46 nsec per loop
$ python -m timeit -n 100 -s "n = 1; c = list(range(1000000))" "n in c"
100 loops, best of 5: 45 nsec per loop
$ python -m timeit -n 100 -s "n = 10000; c = set(range(1000000))" "n in c"
100 loops, best of 5: 60 nsec per loop
$ python -m timeit -n 100 -s "n = 10000; c = list(range(1000000))" "n in c"
100 loops, best of 5: 71.4 usec per loop
The code given to -s is not timed. It lets you set up objects for the timed code to use. n in c is the only code timed now.
I think set creation is taking most of the tim as it involves hashing each element, as mentioned by @tim-peters,.
Here, I have created set and list before performing a search operation and the search time seems to be a lot faster for sets than that of list.
import random
import timeit
def setup(n):
data = list(range(n))
random.shuffle(data)
return set(data), data
def test_set(s, value):
return value in s
def test_list(l, value):
return value in l
n = 1000000
s, l = setup(n)
# Test with a value that's guaranteed to be in both
value_in = random.choice(l)
# Test with a value that's guaranteed not to be in either
value_out = n + 1
print("Searching for a value that exists:")
print("Set:", timeit.timeit(lambda: test_set(s, value_in), number=1000))
print("List:", timeit.timeit(lambda: test_list(l, value_in), number=1000))
print("\nSearching for a value that doesn't exist:")
print("Set:", timeit.timeit(lambda: test_set(s, value_out), number=1000))
print("List:", timeit.timeit(lambda: test_list(l, value_out), number=1000))
Result:
Searching for a value that exists:
Set: 0.00023545200008356915
List: 28.11379308300002
Searching for a value that doesn't exist:
Set: 0.0002436169999100457
List: 52.67750670600003