Как определить, какая часть кода требует оптимизации?

#python-3.x

#python-3.x

Вопрос:

Учитывая два целых числа m, n (1 <= m <= n), найдите все целые числа от m до n, сумма квадратов делителей которых сама по себе является квадратом. 42 — одно из таких чисел.

Код корректно работает на примерах входных данных, но он отклоняется автоматической проверкой кода и сообщает об ошибке тайм-аута и просит оптимизировать код…

 while m < n :
    list_divisors = []
    temp_list = []
    total = 0 

    for number in range (m 1) :
      if m%(number 1) == 0 :
          list_divisors.append(number 1)

    for number in list_divisors :
        total = number*number   
  

Codewars не показывает, для каких тестовых случаев он не выполняется. Это просто показывает ошибку тайм-аута выполнения (12000 мс). Ниже приведены тестовые примеры, пройденные во время проверки образца.

 Test.assert_equals(list_squared(1, 250), [[1, 1], [42, 2500], [246, 84100]])
Test.assert_equals(list_squared(42, 250), [[42, 2500], [246, 84100]])
Test.assert_equals(list_squared(250, 500), [[287, 84100]])
  

Комментарии:

1. Общий ответ на вопрос, заданный в названии, заключается в использовании профилировщика, который сообщит вам, какой процент времени выполнения вашей программы тратится на какие строки. Смотрите также профилировщик выборки третьей стороны py-spy или детерминированные профилировщики стандартной библиотеки, описанные на docs.python.org/3/library/profile.html

2. Вы получили пару ответов на свой вопрос. Если вы находите ответы удовлетворительными, вы можете закрыть свой вопрос, пометив один из них как принятый; или вы можете дождаться поступления новых ответов.

3. «Профилировщик» — новый термин, который я узнал. Кажется, хорошая тема для чтения на выходных! Спасибо.

Ответ №1:

Попробуйте это на основе вашего кода. Никакие данные не сохраняются в списке. Итого — это сумма квадратов целых делителей. Затем, если квадратный корень из этого общего числа является целым числом, верните список.

 import math

def list_squared(number):

    total = 0
    for x in range(1, number 1):
        if number % x == 0:
            total  = x*x

    bounds = math.sqrt(total)
    if math.ceil(bounds) == math.floor(bounds):
        return [number, total]
    else:
        return False


def all_numbers(start, end):
    numbers = []
    for x in range(start, end 1):
        data = list_squared(x)
        if data != False:
            numbers.append(data)

    return numbers

x = all_numbers(1, 10000)
print(x)
  

1 .. 10000 проверок занимают 4,7 секунды. Я уверен, что это можно оптимизировать дальше. Помогает ли это вам?

Еще быстрее

Переключение этих двух строк:

     total = 0
    for x in range(1, number 1):
  

с помощью

     total = 1   number*number
    for x in range(2, math.ceil((number 1)/2)):
  

сократит время выполнения примерно вдвое.

Даже faster..er

 def list_squared(number):
    total = 0
    x = 1
    while x <= math.sqrt(number):
        if number % x == 0:
            if (number/x == x) :
                total  = x*x
            else :
                total  = x*x   (number/x)*(number/x)
        x  = 1

    bounds = math.sqrt(total)
    if math.ceil(bounds) == math.floor(bounds):
        return [number, total]
    else:
        return False
  

Если вы немного измените list_squared, чтобы перебирать только квадратный корень из числа, вы получите время выполнения в полсекунды. Идея, стоящая за этим,https://www.geeksforgeeks.org/find-divisors-natural-number-set-1 /.

Давайте возьмем 42 в качестве числа. Квадратный корень равен 6,48. Давайте просто воспользуемся 6. Начнем с 1. 42 делится на 1. 42 также делится на результат деления, который равен 42.

Перейдите к 2. 42 делится на 2. Результат равен 21. Таким образом, 21 также является целым делителем. Повторите это через 6, и вы охватили все делители для 42. Это сокращает время выполнения до sqrt (n) вместо половины.

Комментарии:

1. «перебирайте только квадратный корень из числа» — Отличный совет! Это работает и проходит проверку.

Ответ №2:

Похоже, вы никогда не обновляете значения m или n . Итак, если m < n is True на первой итерации вашего цикла, это будет всегда, True и ваш цикл while будет бесконечным. Это объясняет время ожидания, вероятно, потому, что Codewars останавливает выполнение вашего кода, если он не завершен через 12000 мс.

Чтобы исправить это, вам придется обновить либо m , либо n внутри вашего while цикла, чтобы в конечном итоге условие m < n приняло значение False , после чего ваш код «выпадет» из while цикла.