Python/project_euler/problem_104/sol1.py
Maxim Smolskiy 4700297b3e
Enable ruff RUF002 rule (#11377)
* Enable ruff RUF002 rule

* Fix

---------

Co-authored-by: Christian Clauss <cclauss@me.com>
2024-04-22 21:51:47 +02:00

142 lines
2.9 KiB
Python

"""
Project Euler Problem 104 : https://projecteuler.net/problem=104
The Fibonacci sequence is defined by the recurrence relation:
Fn = Fn-1 + Fn-2, where F1 = 1 and F2 = 1.
It turns out that F541, which contains 113 digits, is the first Fibonacci number
for which the last nine digits are 1-9 pandigital (contain all the digits 1 to 9,
but not necessarily in order). And F2749, which contains 575 digits, is the first
Fibonacci number for which the first nine digits are 1-9 pandigital.
Given that Fk is the first Fibonacci number for which the first nine digits AND
the last nine digits are 1-9 pandigital, find k.
"""
import sys
sys.set_int_max_str_digits(0)
def check(number: int) -> bool:
"""
Takes a number and checks if it is pandigital both from start and end
>>> check(123456789987654321)
True
>>> check(120000987654321)
False
>>> check(1234567895765677987654321)
True
"""
check_last = [0] * 11
check_front = [0] * 11
# mark last 9 numbers
for _ in range(9):
check_last[int(number % 10)] = 1
number = number // 10
# flag
f = True
# check last 9 numbers for pandigitality
for x in range(9):
if not check_last[x + 1]:
f = False
if not f:
return f
# mark first 9 numbers
number = int(str(number)[:9])
for _ in range(9):
check_front[int(number % 10)] = 1
number = number // 10
# check first 9 numbers for pandigitality
for x in range(9):
if not check_front[x + 1]:
f = False
return f
def check1(number: int) -> bool:
"""
Takes a number and checks if it is pandigital from END
>>> check1(123456789987654321)
True
>>> check1(120000987654321)
True
>>> check1(12345678957656779870004321)
False
"""
check_last = [0] * 11
# mark last 9 numbers
for _ in range(9):
check_last[int(number % 10)] = 1
number = number // 10
# flag
f = True
# check last 9 numbers for pandigitality
for x in range(9):
if not check_last[x + 1]:
f = False
return f
def solution() -> int:
"""
Outputs the answer is the least Fibonacci number pandigital from both sides.
>>> solution()
329468
"""
a = 1
b = 1
c = 2
# temporary Fibonacci numbers
a1 = 1
b1 = 1
c1 = 2
# temporary Fibonacci numbers mod 1e9
# mod m=1e9, done for fast optimisation
tocheck = [0] * 1000000
m = 1000000000
for x in range(1000000):
c1 = (a1 + b1) % m
a1 = b1 % m
b1 = c1 % m
if check1(b1):
tocheck[x + 3] = 1
for x in range(1000000):
c = a + b
a = b
b = c
# perform check only if in tocheck
if tocheck[x + 3] and check(b):
return x + 3 # first 2 already done
return -1
if __name__ == "__main__":
print(f"{solution() = }")