Вместо того, чтобы на самом деле найти все соответствующие факторы, мы можем гораздо более эффективно вычислить число возможных, делая разложение на простые множители.
Например,
288 == 2**5 * 3**2
и число собственных факторов
(5 + 1) * (2 + 1) - 1
^ ^ ^
number number omit one case:
of twos of threes 5 2s and 2 3s == 288,
used in used in which is not a proper
factor, factor factor of itself
0..5
(six possible
values)
Чтобы сделать разложение на простые множители, мы должны начать с генерации простых чисел:
def primes(known_primes=[7, 11, 13, 17, 19, 23, 29]):
"""
Generate every prime number in ascending order
"""
# 2, 3, 5 wheel
yield from (2, 3, 5)
yield from known_primes
# The first time the generator runs, known_primes
# contains all primes such that 5 < p < 2 * 3 * 5
# After each wheel cycle the list of known primes
# will be added to.
# We need to figure out where to continue from,
# which is the next multiple of 30 higher than
# the last known_prime:
base = 30 * (known_primes[-1] // 30 + 1)
new_primes = []
while True:
# offs is chosen so 30*i + offs cannot be a multiple of 2, 3, or 5
for offs in (1, 7, 11, 13, 17, 19, 23, 29):
k = base + offs # next prime candidate
for p in known_primes:
if not k % p:
# found a factor - not prime
break
elif p*p > k:
# no smaller prime factors - found a new prime
new_primes.append(k)
break
if new_primes:
yield from new_primes
known_primes.extend(new_primes)
new_primes = []
base += 30
, который может быть проверен l икэ
from itertools import islice
print(list(islice(primes(), 500)))
давая
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, ...
Теперь, когда у нас есть простые числа, мы можем рассчитывать вхождения каждого простого фактора как так:
def prime_factor_count(n):
"""
Factorize n and yield (factor, count) for each distinct factor
"""
if n < 2:
return
else:
for p in primes():
count = 0
while not n % p:
count += 1
n //= p
if count:
yield (p, count)
if n == 1:
# number is fully factored
break
elif p*p > n:
# no smaller prime factors - remainder is prime
yield (n, 1)
break
, который мы можем проверить, как
print(list(prime_factor_count(288))) # => [(2, 5), (3, 2)]
, который вы должны признать сверху, 288 == 2**5 * 3**2
.Теперь мы можем
def num_proper_factors(n):
total_factors = 1
for factor, count in prime_factor_count(n):
total_factors *= (count + 1)
return total_factors - 1
, который проверяет, как
print(num_proper_factors(288)) # => 17
и, наконец,
def num_with_most_divisors(lst):
return max(lst, key=num_proper_factors)
QED.
Почему dict? просто используйте 'find_divisor' в качестве ключевой функции – Copperfield
Хороший вызов. Я думал, на случай, если они захотят вернуть счет или что-то еще ... :) Я обновлю его, чтобы использовать ваше предложение, хотя и намного чище – rofls