Это мой первый код:
def isAnagram(s,t):
if len(s)!=len(t):
return False
for i in s:
if s.count(i)!=t.count(i):
return False
return True
Это мой второй код:
def isAnagram(s,t):
if len(s)!=len(t):
return False
for i in set(s):
if s.count(i)!=t.count(i):
return False
return True
Это мой третий код:
def isAnagram(s,t):
if len(s)!=len(t):
return False
for i in set(s[:]):
if s.count(i)!=t.count(i):
return False
return True
Я не понимаю, почему замена s
на set(s)
в 4-й строке требует меньше времени для выполнения, а замена на set(s[:])
даже лучше, чем два других оператора.
Может ли кто-нибудь помочь мне узнать, почему это происходит?
Я не могу придумать причину, почему set(s[:])
лучше, чем set(s)
. Это должно быть немного хуже, потому что он должен сделать копию списка, прежде чем преобразовать его в набор.
В зависимости от того, как именно тестируется код, более поздние запуски могут выполняться быстрее из-за подогрева кеша.
Кроме того, вы можете уменьшить свою функцию до return sorted(s) == sorted(t)
, чтобы проверить наличие анаграмм.
Важно показать, как вы тестировали. Если вы не использовали timeit
для прогрева кэшей и отключения сборки мусора, то тест, вероятно, ненадежен. (хотя это ставит нас здесь в странное положение, потому что s[:]
создает дополнительную работу по сборке мусора, поэтому в реальной ситуации это очень сильно снижает пропускную способность, даже если этот эффект задерживается)
После выполнения %timeit
я обнаружил, что наблюдение @Barmar верно. Вы должны выполнить timeit для этих функций.
set(s[:])
дороже по сравнению с set(s)
Для этих 4 функций:
def isAnagram(s,t):
if len(s)!=len(t):
return False
a = set(s)
for i in a:
if s.count(i)!=t.count(i):
return False
return True
def isAnagram1(s,t):
if len(s)!=len(t):
return False
a = set(s[:])
for i in a:
if s.count(i)!=t.count(i):
return False
return True
def isAnagram2(s,t):
if len(s)!=len(t):
return False
for i in set(s):
if s.count(i)!=t.count(i):
return False
return True
def isAnagram3(s,t):
if len(s)!=len(t):
return False
for i in set(s[:]):
if s.count(i)!=t.count(i):
return False
return True
a = "abcde"
b = "edabc"
%timeit isAnagram(a, b)
%timeit isAnagram1(a,b)
%timeit isAnagram2(a,b)
%timeit isAnagram3(a,b)
Я получил следующий вывод:
958 ns ± 5.37 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
1.01 µs ± 17.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
967 ns ± 9.61 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
987 ns ± 2.54 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Также самым быстрым методом проверки анаграммы будет оператор XOR.
def isAnagramXOR(s, t):
res = 0
for i,j in zip(s, t):
res ^= ord(i) ^ ord(j)
return not bool(res)
Производительность: 667 ns ± 2.54 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Преобразование строки в набор удалит все дубликаты, поэтому вы будете повторять меньшее количество раз.