11
11
How many starting numbers below ten million will arrive at 89?
12
12
"""
13
13
14
-
15
- DIGITS_SQUARED = [digit ** 2 for digit in range (10 )]
14
+ DIGITS_SQUARED = [sum (int (c , 10 ) ** 2 for c in i .__str__ ()) for i in range (100000 )]
16
15
17
16
18
17
def next_number (number : int ) -> int :
18
+
19
19
"""
20
20
Returns the next number of the chain by adding the square of each digit
21
21
to form a new number.
@@ -28,15 +28,29 @@ def next_number(number: int) -> int:
28
28
>>> next_number(32)
29
29
13
30
30
"""
31
+
31
32
sum_of_digits_squared = 0
32
33
while number :
33
- sum_of_digits_squared += DIGITS_SQUARED [number % 10 ]
34
- number //= 10
34
+
35
+ # Increased Speed Slightly by checking every 5 digits together.
36
+ sum_of_digits_squared += DIGITS_SQUARED [number % 100000 ]
37
+ number //= 100000
35
38
36
39
return sum_of_digits_squared
37
40
38
41
39
- CHAINS = {1 : True , 58 : False }
42
+ # There are 2 Chains made,
43
+ # One ends with 89 with the chain member 58 being the one which when declared first,
44
+ # there will be the least number of iterations for all the members to be checked.
45
+
46
+ # The other one ends with 1 and has only one element 1.
47
+
48
+ # So 58 and 1 are chosen to be declared at the starting.
49
+
50
+ # Changed dictionary to an array to quicken the solution
51
+ CHAINS : list [bool | None ] = [None ] * 10000000
52
+ CHAINS [0 ] = True
53
+ CHAINS [57 ] = False
40
54
41
55
42
56
def chain (number : int ) -> bool :
@@ -54,11 +68,16 @@ def chain(number: int) -> bool:
54
68
>>> chain(1)
55
69
True
56
70
"""
57
- if number in CHAINS :
58
- return CHAINS [number ]
71
+
72
+ if CHAINS [number - 1 ] is not None :
73
+ return CHAINS [number - 1 ] # type: ignore
59
74
60
75
number_chain = chain (next_number (number ))
61
- CHAINS [number ] = number_chain
76
+ CHAINS [number - 1 ] = number_chain
77
+
78
+ while number < 10000000 :
79
+ CHAINS [number - 1 ] = number_chain
80
+ number *= 10
62
81
63
82
return number_chain
64
83
@@ -74,12 +93,15 @@ def solution(number: int = 10000000) -> int:
74
93
>>> solution(10000000)
75
94
8581146
76
95
"""
77
- return sum (1 for i in range (1 , number ) if not chain (i ))
96
+ for i in range (1 , number ):
97
+ if CHAINS [i ] is None :
98
+ chain (i + 1 )
99
+
100
+ return CHAINS [:number ].count (False )
78
101
79
102
80
103
if __name__ == "__main__" :
81
104
import doctest
82
105
83
106
doctest .testmod ()
84
-
85
107
print (f"{ solution () = } " )
0 commit comments