помогите оптимизировать код для решения задачи егэ по информатика(25)

Назовём маской числа последовательность цифр, в которой также могут встречаться следующие символы:

символ ? означает ровно одну произвольную цифру; символ * означает любую последовательность цифр произвольной длины; в том числе * может задавать и пустую последовательность. Например, маске 123*4?5 соответствуют числа 123405 и 12300405.

Среди натуральных чисел, не превышающих 10⁷, найдите все числа, удовлетворяющие маске 34?8*9 имеющие более 4 простых делителей (не равных самому числу и 1). В ответ в порядке возрастания выпишите подходящие числа и их наибольшие простые делители.

мой код:

n = 0
def izi(n):
  d = 0
  dn = []
  for i in range(2, int(n/2) + 1):
    for j in range(2, (i//2) + 1):
      if i % j == 0:
        break
    if n % i == 0:
      d += 1
      dn.append(i)
  return dn
sp = []
for z in range(11):
  n = f'34{z}89'
  K = izi(int(n))
  if len(K) > 4:
    print(K)
  for x in range(11):
    n = f'34{z}8{x}9'
    K = izi(int(n))
    if len(K) > 4:
      print(K)
    for y in range(11):
      n = f'34{z}8{x}{y}9'
      K = izi(int(n))
      if len(K) > 4:
        print(K)
  

помогите увеличить скорость выполнения кода


Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

Функция izi ошибается: izi(8)[2, 4], izi(12)[2, 3, 4, 6]. В списке простых собственных делителей есть не простые числа 4 и 6. Это потому что цикл по j не работает:

    for j in range(2, (i//2) + 1):
      if i % j == 0:
        break

Этот код буквально ничего не делает. Перебирает значения в цикле, выходит из цикла и ничего не делает. Можно предположить что вы хотели проверить что кандидат в делители i простой, то есть не делится ни на какой j, но не получилось.

Ваш код можно исправить так:

def izi(n):
    dn = []
    for i in range(2, n // 2 + 1):
        for j in range(2, i // 2 + 1):
            if i % j == 0:
                break
        else:
            if n % i == 0:
                dn.append(i)
    return dn

Во внутреннем цикле появился блок else:. Для цикла он запускается, если в цикле не вызывался break. А если break не вызывался, то i ни на что не делится, значит оно простое.

Работает. Теперь можно оптимизировать. Условие if n % i == 0: поднимем наверх цикла. Зачем проверять простоту числа, которое не делитель n?

def izi(n):
    dn = []
    for i in range(2, n // 2 + 1):
        if n % i == 0:
            for j in range(2, i // 2 + 1):
                if i % j == 0:
                    break
            else:
                dn.append(i)
    return dn

В таком виде программа начинает выдавать результаты. Пока я это пишу получились такие ответы:

[3, 7, 37, 41, 107]
[3, 7, 17, 61, 157]
[3, 11, 13, 61, 131]
[3, 17, 23, 37, 79]
[3, 11, 13, 229, 349]
[7, 13, 23, 31, 53]
[3, 7, 17, 41, 79]
...

Печатается не то что нужно, но хоть что-то. Избавиться от проверки простоты i можно если n делить на найденный делитель, чтобы исключить его появление в будущем в составе других делителей. Цикл for изменился на while потому что верхняя граница цикла теперь меняется. В конце в список делителей добавляется n, который к этому моменту сам стал простым делителем:

def izi(n):
    dn = []
    i = 2
    while i <= n // 2:
        if n % i == 0:
            # очистка n от простого множителя i
            while n % i == 0:
                n //= i
            dn.append(i)
        i += 1
    if n > 1:
        dn.append(n)
    return dn

Перебирать i достаточно до корня квадратного из n:

def izi(n):
    dn = []
    i = 2
    while i * i <= n:
        if n % i == 0:
            # очистка n от простого множителя i
            while n % i == 0:
                n //= i
            dn.append(i)
        i += 1
    if n > 1:
        dn.append(i)
    return dn

Теперь работает очень быстро. Дальше я оптимизировать не буду. Поправьте печать сами.

→ Ссылка