-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEuler074.py
40 lines (30 loc) · 1.69 KB
/
Euler074.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Solution to Project Euler problem 74 by tdnzr.
# Quite efficient solution based on using knowledge about chains.
# This problem is related to various chains-related problems, e.g. 12, 92, 95 (from which I borrowed some code), ...
from math import factorial
def calcDigitFactorialSum(number):
return sum([factorial(int(digit)) for digit in str(number)])
def run():
chainsList = []
for i in range(1_000_000): # starting numbers *below* one million
chain = [] # I originally figured turning this into a set might improve efficiency (faster membership testing; no need to preserve order), but the result was slower.
number = i
# Construct the chain beginning with "number":
chain.append(number) # i is the first element of the chain
while True:
number = calcDigitFactorialSum(number)
# Once we've reached an element < i, we've already computed the corresponding chain,
# so we can reuse that result. This step saves *a lot* of time.
# Otherwise, stop the chain once it begins repeating itself.
# If neither condition holds, append the number to the chain.
if number < i:
chain += chainsList[number] # 1-based index. The chain beginning with the number 1 has the index 1.
break
elif number in chain or len(chain) > 60:
break
else:
chain.append(number)
chainsList.append(chain)
return sum([1 for chain in chainsList if len(chain) == 60])
if __name__ == "__main__":
print(f"{run()} digit factorial chains with a starting number below one million contain exactly sixty non-repeating terms.")