Skip to content

Commit 83b8b3c

Browse files
tacitvenomgithub-actions
tacitvenom
and
github-actions
authored
Fixes: #3869: Optimize CI runtime of Project Euler's Problem 74's Solution 2 (#3893)
* Fixes: #3869: Optimize Project Euler's Problem 74's Solution 2 * updating DIRECTORY.md Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
1 parent 2885a8c commit 83b8b3c

File tree

1 file changed

+39
-29
lines changed

1 file changed

+39
-29
lines changed

Diff for: project_euler/problem_074/sol2.py

+39-29
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616
the chains of non repeating items.
1717
The generation of the chain stops before a repeating item
1818
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.
19+
After generating each chain, the length is checked and the
20+
counter increases.
2021
"""
2122

23+
factorial_cache = {}
24+
factorial_sum_cache = {}
25+
2226

2327
def factorial(a: int) -> int:
2428
"""Returns the factorial of the input a
@@ -36,18 +40,23 @@ def factorial(a: int) -> int:
3640
if a < 0:
3741
raise ValueError("Invalid negative input!", a)
3842

43+
if a in factorial_cache:
44+
return factorial_cache[a]
45+
3946
# The case of 0! is handled separately
4047
if a == 0:
41-
return 1
48+
factorial_cache[a] = 1
4249
else:
4350
# use a temporary support variable to store the computation
51+
temporary_number = a
4452
temporary_computation = 1
4553

46-
while a > 0:
47-
temporary_computation *= a
48-
a -= 1
54+
while temporary_number > 0:
55+
temporary_computation *= temporary_number
56+
temporary_number -= 1
4957

50-
return temporary_computation
58+
factorial_cache[a] = temporary_computation
59+
return factorial_cache[a]
5160

5261

5362
def factorial_sum(a: int) -> int:
@@ -57,7 +66,8 @@ def factorial_sum(a: int) -> int:
5766
>>> factorial_sum(69)
5867
363600
5968
"""
60-
69+
if a in factorial_sum_cache:
70+
return factorial_sum_cache[a]
6171
# Prepare a variable to hold the computation
6272
fact_sum = 0
6373

@@ -67,17 +77,15 @@ def factorial_sum(a: int) -> int:
6777
"""
6878
for i in str(a):
6979
fact_sum += factorial(int(i))
70-
80+
factorial_sum_cache[a] = fact_sum
7181
return fact_sum
7282

7383

7484
def solution(chain_length: int = 60, number_limit: int = 1000000) -> int:
7585
"""Returns the number of numbers that produce
7686
chains with exactly 60 non repeating elements.
77-
>>> solution(60,1000000)
78-
402
79-
>>> solution(15,1000000)
80-
17800
87+
>>> solution(10, 1000)
88+
26
8189
"""
8290

8391
# the counter for the chains with the exact desired length
@@ -86,25 +94,27 @@ def solution(chain_length: int = 60, number_limit: int = 1000000) -> int:
8694
for i in range(1, number_limit + 1):
8795

8896
# The temporary list will contain the elements of the chain
89-
chain_list = [i]
97+
chain_set = {i}
98+
len_chain_set = 1
99+
last_chain_element = i
90100

91101
# 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
102+
new_chain_element = factorial_sum(last_chain_element)
103+
104+
# Stop computing the chain when you find a repeating item
105+
# or the length it greater then the desired one.
106+
107+
while new_chain_element not in chain_set and len_chain_set <= chain_length:
108+
chain_set.add(new_chain_element)
109+
110+
len_chain_set += 1
111+
last_chain_element = new_chain_element
112+
new_chain_element = factorial_sum(last_chain_element)
113+
114+
# If the while exited because the chain list contains the exact amount
115+
# of elements increase the counter
116+
if len_chain_set == chain_length:
117+
chain_counter += 1
108118

109119
return chain_counter
110120

0 commit comments

Comments
 (0)