You can speed things up by dividing n
by the obtained value in each iteration step. This way you decrease the number you are iterating. I would implement something like this (not yet sure if this is optimal and results in the lowest number of operations):
from math import sqrt
def pf(n):
if n == 1:
return
if n % 2 == 0:
print(2)
pf(n/2)
return
for i in range(3, int(sqrt(n))+1, 2):
if n % i == 0:
for j in range(3, int(sqrt(i))+1, 2):
if i % j == 0:
break
else:
print(i)
pf(n/i)
return
print(n)
Note, if using the improvement of looping until the root of the number we omit the case that the number itself is a prime number. However, if the function does not result any prime factors it is save to assume that the input is a prime number itself.
The return
statements stop the main loop (and the function) after the recursive call. So each call of the function only results in one value and a call for the function on the result of the division of the number by its found prime.
If you make a set with all the prime numbers and check if the value is in this set you will win some time, instead of looping over all values.
Compared to the non-recursive solution by jonrsharpe this one is almost four times as fast:
>>> print timeit.timeit("pf(600851475143)", setup="from __main__ import pf", number=1)
71
839
1471
6857
0.00985789299011
>>> print timeit.timeit("pf2(600851475143)", setup="from __main__ import pf2", number=1)
71
839
1471
6857
0.0450129508972
The implementation is limited by the overflow limit of range()
, which results in an overflow for the input value (600851475143**2)+1
. More details on the maximum size for range
can be found in this question: Python: Range() maximum size; dynamic or static?
A possible issue with this solution could be that the maximum recursion depth is achieved. For more details on that visit this question: Maximum recursion depth