Решение, представленное @agf, великолепно, но можно достичь ~ 50% более быстрого выполнения для произвольного нечетного числа, проверяя на четность.Поскольку факторы нечетного числа всегда сами по себе нечетны, нет необходимости проверять их при работе с нечетными числами.
Я только что начал решать Project Euler .В некоторых задачах проверка делителей вызывается внутри двух вложенных циклов for
, и поэтому выполнение этой функции является существенным.
Объединяя этот факт с превосходным решением agf, я в итоге получил следующую функцию:
from math import sqrt
def factors(n):
step = 2 if n%2 else 1
return set(reduce(list.__add__,
([i, n//i] for i in range(1, int(sqrt(n))+1, step) if n % i == 0)))
Однако при небольших значениях (~ <100) дополнительные издержки, связанные с этим изменением, могут привести к более длительной работе функции. </p>
Я провел несколько тестов, чтобы проверить скорость,Ниже приведен код, используемый.Чтобы получить различные графики, я изменил X = range(1,100,1)
соответственно.
import timeit
from math import sqrt
from matplotlib.pyplot import plot, legend, show
def factors_1(n):
step = 2 if n%2 else 1
return set(reduce(list.__add__,
([i, n//i] for i in range(1, int(sqrt(n))+1, step) if n % i == 0)))
def factors_2(n):
return set(reduce(list.__add__,
([i, n//i] for i in range(1, int(sqrt(n)) + 1) if n % i == 0)))
X = range(1,100000,1000)
Y = []
for i in X:
f_1 = timeit.timeit('factors_1({})'.format(i), setup='from __main__ import factors_1', number=10000)
f_2 = timeit.timeit('factors_2({})'.format(i), setup='from __main__ import factors_2', number=10000)
Y.append(f_1/f_2)
plot(X,Y, label='Running time with/without parity check')
legend()
show()
X = диапазон (1100,1)
Здесь нет существенной разницы, но с большими числами преимущество очевидно:
X = диапазон (1 100 000 1000) (только нечетные числа)
X = диапазон (2 100 000 100) (только четные числа)
X = диапазон (1 100 000 1001) (переменный паритет)