from functools import lru_cache @lru_cache(maxsize=10) def fac(n): r = 1 if n <= 1: return 1 for i in range(2, n + 1): r *= i return r @lru_cache(maxsize=1000000) def get_factorial_sum(n): s = 0 for d in get_digits(n): s += fac(d) return s current_numbers_set = set() @lru_cache(maxsize=10000000) def get_chain_length(n): """ Could be further optimized by caching all permutations of the given number. All permutations of a number have the same factorial sum because they consist of the same digits. """ global current_numbers_set next_value = get_factorial_sum(n) if next_value in current_numbers_set: return 1 else: current_numbers_set.add(next_value) return 1 + get_chain_length(next_value) def get_digits(n): return map(int, str(n)) def euler_074(): c = 0 for n in range(10**6): global current_numbers_set current_numbers_set = set([n]) chain_len = get_chain_length(n) if chain_len == 60: # print("n: {} length: {}".format(n, chain_len)) c += 1 return c if __name__ == "__main__": print("e074.py: " + str(euler_074())) assert(euler_074() == 402)