Мне нужна помощь в оптимизации моего кода codewars, который называется факториальной декомпозицией. Цель ката состоит в том, чтобы разложить n! (факториал n) на его простые множители. Результат должен возвращать такую строку;
п = 12; разложить(12) -> "2^10 * 3^5 * 5^2 * 7 * 11"
Мой код работает правильно и проходит тесты, но когда я пытаюсь попробовать свой код, я получаю ошибку тайм-аута. Вот моя попытка;
def decomp(n):
number_count = {2 : 1}
return_str = ""
def add_list(num):
if num not in number_count:
number_count[num] = 1
else:
number_count[num] += 1
for x in range(n, 1, -1):
add = False
for y in range(1, x):
if x == 1 or y == 1: continue
a = True
while a:
if x % y == 0 and y != 1:
x = int(x / y)
add_list(y)
else:
a = False
add = True
if add and x != 1:
add_list(x)
number_count3 = {k: number_count[k] for k in sorted(number_count.keys())}
for x, y in number_count3.items():
if y == 1:
return_str += str(x) + " * "
else:
return_str += str(x) + "^" + str(y) + " * "
return return_str[:-3]
Вы можете улучшить это, воспользовавшись некоторой теорией чисел. Для факториала типа 12!
будет
12//2 + 6//2 + 3//2
коэффициенты два. Аналогичные закономерности будут справедливы и для всех остальных простых чисел. Таким образом, вы можете составить список простых чисел меньше n
и быстро разложить экспоненту примерно так:
def primes(n):
n += 1
sieve = [True] * n
for i in range(3,int(n**0.5)+1,2):
if sieve[i]:
sieve[i*i::2*i]=[False]*((n-i*i-1)//(2*i)+1)
return [2] + [i for i in range(3,n,2) if sieve[i]]
def mults(n):
res = []
for p in primes(n):
rest = n
s = 0
while rest >0:
j = rest // p
s += j
rest = j
if s > 1:
res.append(f'{p}^{s}')
else:
res.append(str(p))
return ' * '.join(res)
mults(16)
Результат
'2^15 * 3^6 * 5^3 * 7^2 * 11 * 13'
Сравнение времени с оригиналом дает:
%timeit decomp(22)
54 µs ± 201 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit mults(22)
8.23 µs ± 30.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Что кажется достойным улучшением. Разница более заметна с большими n
:
%timeit decomp(130)
823 µs ± 965 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit mults(130)
25.4 µs ± 73 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Это хороший улов @UysalAltas, спасибо. Я отредактирую ответ, когда вернусь за компьютер.
Спасибо за ваш ответ. Потрясающий подход. Вот только одна маленькая проблема. Функция «простые числа» не ищет n сама. Если n — простое число, ответ получается с одним множителем. Например, для 5 - "2^3 * 3" . Должно быть - "2^3 * 3 * 5". Я решил это, добавив n += 1 начало простой функции.