Вы можете немного изменить рекурсивную версию:
def Game(x):
if x == 0: return True
s = set(digit for digit in str(x) if digit != '0')
return any(not Game(x-int(digit)) for digit in s)
Таким образом, вы не проверяете цифры несколько раз. Например, если вы делаете 111, вам не нужно смотреть на 110 три раза.
Я не уверен, считается ли это итеративной версией исходного алгоритма, который вы представили, но вот памятная итерационная версия:
import Queue
def Game2(x):
memo = {}
memo[0] = True
calc_dep = {}
must_calc = Queue.Queue()
must_calc.put(x)
while not must_calc.empty():
n = must_calc.get()
if n and n not in calc_dep:
s = set(int(c) for c in str(n) if c != '0')
elems = [n - digit for digit in s]
calc_dep[n] = elems
for new_elem in elems:
if new_elem not in calc_dep:
must_calc.put(new_elem)
for k in sorted(calc_dep.keys()):
v = calc_dep[k]
#print k, v
memo[k] = any(not memo[i] for i in v)
return memo[x]
Сначала вычисляется набор чисел, от которого зависит вход x. Затем он рассчитывает эти числа, начиная с нижней части и двигаясь в направлении х.
Код очень быстрый из-за теста для calc_dep. Это позволяет избежать расчета нескольких зависимостей. В результате он может выполнить Game (10000) менее чем за 400 миллисекунд, тогда как оригинал занимает - я не знаю, как долго. Долгое время.
Вот измерения производительности:
Elapsed: 1000 0:00:00.029000
Elapsed: 2000 0:00:00.044000
Elapsed: 4000 0:00:00.086000
Elapsed: 8000 0:00:00.197000
Elapsed: 16000 0:00:00.461000
Elapsed: 32000 0:00:00.969000
Elapsed: 64000 0:00:01.774000
Elapsed: 128000 0:00:03.708000
Elapsed: 256000 0:00:07.951000
Elapsed: 512000 0:00:19.148000
Elapsed: 1024000 0:00:34.960000
Elapsed: 2048000 0:01:17.960000
Elapsed: 4096000 0:02:55.013000
Это довольно быстро.