Skip to content

Commit 70b6a99

Browse files
GGn0peRFectBeliever
authored andcommitted
Add solution to problem 74 (TheAlgorithms#3110)
* Add solution to problem 74 * Fix typo * Edit unnecessary comment * Rename folder, add default params in solution() * Rename file to solve conflicts * Fix doctests
1 parent d864f1f commit 70b6a99

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

Diff for: project_euler/problem_074/sol2.py

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
"""
2+
Project Euler Problem 074: https://projecteuler.net/problem=74
3+
4+
Starting from any positive integer number
5+
it is possible to attain another one summing the factorial of its digits.
6+
7+
Repeating this step, we can build chains of numbers.
8+
It is not difficult to prove that EVERY starting number
9+
will eventually get stuck in a loop.
10+
11+
The request is to find how many numbers less than one million
12+
produce a chain with exactly 60 non repeating items.
13+
14+
Solution approach:
15+
This solution simply consists in a loop that generates
16+
the chains of non repeating items.
17+
The generation of the chain stops before a repeating item
18+
or if the size of the chain is greater then the desired one.
19+
After generating each chain, the length is checked and the counter increases.
20+
"""
21+
22+
23+
def factorial(a: int) -> int:
24+
"""Returns the factorial of the input a
25+
>>> factorial(5)
26+
120
27+
28+
>>> factorial(6)
29+
720
30+
31+
>>> factorial(0)
32+
1
33+
"""
34+
35+
# The factorial function is not defined for negative numbers
36+
if a < 0:
37+
raise ValueError("Invalid negative input!", a)
38+
39+
# The case of 0! is handled separately
40+
if a == 0:
41+
return 1
42+
else:
43+
# use a temporary support variable to store the computation
44+
temporary_computation = 1
45+
46+
while a > 0:
47+
temporary_computation *= a
48+
a -= 1
49+
50+
return temporary_computation
51+
52+
53+
def factorial_sum(a: int) -> int:
54+
"""Function to perform the sum of the factorial
55+
of all the digits in a
56+
57+
>>> factorial_sum(69)
58+
363600
59+
"""
60+
61+
# Prepare a variable to hold the computation
62+
fact_sum = 0
63+
64+
""" Convert a in string to iterate on its digits
65+
convert the digit back into an int
66+
and add its factorial to fact_sum.
67+
"""
68+
for i in str(a):
69+
fact_sum += factorial(int(i))
70+
71+
return fact_sum
72+
73+
74+
def solution(chain_length: int = 60, number_limit: int = 1000000) -> int:
75+
"""Returns the number of numbers that produce
76+
chains with exactly 60 non repeating elements.
77+
>>> solution(60,1000000)
78+
402
79+
>>> solution(15,1000000)
80+
17800
81+
"""
82+
83+
# the counter for the chains with the exact desired length
84+
chain_counter = 0
85+
86+
for i in range(1, number_limit + 1):
87+
88+
# The temporary list will contain the elements of the chain
89+
chain_list = [i]
90+
91+
# The new element of the chain
92+
new_chain_element = factorial_sum(chain_list[-1])
93+
94+
""" Stop computing the chain when you find a repeating item
95+
or the length it greater then the desired one.
96+
"""
97+
while not (new_chain_element in chain_list) and (
98+
len(chain_list) <= chain_length
99+
):
100+
chain_list += [new_chain_element]
101+
102+
new_chain_element = factorial_sum(chain_list[-1])
103+
104+
""" If the while exited because the chain list contains the exact amount of elements
105+
increase the counter
106+
"""
107+
chain_counter += len(chain_list) == chain_length
108+
109+
return chain_counter
110+
111+
112+
if __name__ == "__main__":
113+
import doctest
114+
115+
doctest.testmod()
116+
print(f"{solution()}")

0 commit comments

Comments
 (0)