Project Euler: 092 decreased the time (#6627)

* Added explanation and increased speed of the solution of problem 092

* updating DIRECTORY.md

* Added temporary fix to the failing of problem 104

* Reduced few seconds by minor improvements

* Update sol.py

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
Co-authored-by: Christian Clauss <cclauss@me.com>
This commit is contained in:
Saksham1970 2022-10-30 15:40:16 +05:30 committed by GitHub
parent 00dfad9d20
commit 84facb78b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -11,11 +11,11 @@ What is most amazing is that EVERY starting number will eventually arrive at 1 o
How many starting numbers below ten million will arrive at 89? How many starting numbers below ten million will arrive at 89?
""" """
DIGITS_SQUARED = [sum(int(c, 10) ** 2 for c in i.__str__()) for i in range(100000)]
DIGITS_SQUARED = [digit**2 for digit in range(10)]
def next_number(number: int) -> int: def next_number(number: int) -> int:
""" """
Returns the next number of the chain by adding the square of each digit Returns the next number of the chain by adding the square of each digit
to form a new number. to form a new number.
@ -28,15 +28,29 @@ def next_number(number: int) -> int:
>>> next_number(32) >>> next_number(32)
13 13
""" """
sum_of_digits_squared = 0 sum_of_digits_squared = 0
while number: while number:
sum_of_digits_squared += DIGITS_SQUARED[number % 10]
number //= 10 # Increased Speed Slightly by checking every 5 digits together.
sum_of_digits_squared += DIGITS_SQUARED[number % 100000]
number //= 100000
return sum_of_digits_squared return sum_of_digits_squared
CHAINS = {1: True, 58: False} # There are 2 Chains made,
# One ends with 89 with the chain member 58 being the one which when declared first,
# there will be the least number of iterations for all the members to be checked.
# The other one ends with 1 and has only one element 1.
# So 58 and 1 are chosen to be declared at the starting.
# Changed dictionary to an array to quicken the solution
CHAINS: list[bool | None] = [None] * 10000000
CHAINS[0] = True
CHAINS[57] = False
def chain(number: int) -> bool: def chain(number: int) -> bool:
@ -54,11 +68,16 @@ def chain(number: int) -> bool:
>>> chain(1) >>> chain(1)
True True
""" """
if number in CHAINS:
return CHAINS[number] if CHAINS[number - 1] is not None:
return CHAINS[number - 1] # type: ignore
number_chain = chain(next_number(number)) number_chain = chain(next_number(number))
CHAINS[number] = number_chain CHAINS[number - 1] = number_chain
while number < 10000000:
CHAINS[number - 1] = number_chain
number *= 10
return number_chain return number_chain
@ -74,12 +93,15 @@ def solution(number: int = 10000000) -> int:
>>> solution(10000000) >>> solution(10000000)
8581146 8581146
""" """
return sum(1 for i in range(1, number) if not chain(i)) for i in range(1, number):
if CHAINS[i] is None:
chain(i + 1)
return CHAINS[:number].count(False)
if __name__ == "__main__": if __name__ == "__main__":
import doctest import doctest
doctest.testmod() doctest.testmod()
print(f"{solution() = }") print(f"{solution() = }")