Это добавляет пару оптимизаций к хорошему решению @ GreggLind, сокращая время выполнения в два раза:
def is_palindrome(n):
s = str(n)
return s == s[::-1]
def biggest():
big_x, big_y, max_seen = 0,0, 0
for x in xrange(999,99,-1):
# Optim. 1: Nothing in any row from here on can be bigger.
if x*x < max_seen: break
for y in xrange(x, 99,-1): # so we don't double count
# Optim. 2: break, not continue
if x*y < max_seen: break # since we're decreasing,
# nothing else in the row can be bigger
if is_palindrome(x*y):
big_x, big_y, max_seen = x,y, x*y
return big_x,big_y,max_seen
biggest()
# (993, 913, 906609)
Линия
if x*x < max_seen: break
означает, что как только мы доберемся до точки, где x меньше, чем sqrt самого большого палиндрома, который мы уже видели, нам не только не нужно исследовать больше факторов в этой строке; нам даже не нужно исследовать больше строк, так как все оставшиеся строки будут начинаться с числа, меньшего текущего значения x.
Это не уменьшает количество раз, которое мы вызываем is_palindrome()
, но означает гораздо меньшее количество итераций внешнего цикла. Значение x
, на которое он разбивается, равно 952, поэтому мы исключили проверку 853 строк (хотя и «меньших», благодаря другим break
).
Я также заметил, что
if x*y < max_seen: continue
должно быть
if x*y < max_seen: break
Мы пытаемся замкнуть всю строку, а не только текущую итерацию внутреннего цикла.
Когда я запускал этот скрипт с использованием cProfile , совокупное время для biggest()
составляло в среднем около 56 мсек до оптимизации. Оптимизация сократилась до 23 мсек. Любая оптимизация принесла бы большую часть этого улучшения, но первая немного более полезна, чем вторая.