Files
SolutionEuler/solutions/0037.TruncatablePrimes/euler_37.py
Sidney Zhang 5b1a9f0e4e feat(euler_37.py):添加截断素数验证函数和性能计时器
♻️ refactor(euler_37.py):优化素数判断算法和代码结构
 test(euler_37.py):完善截断素数检测逻辑和主程序
2026-01-07 18:33:01 +08:00

88 lines
2.2 KiB
Python

"""
The number 3797 has an interesting property.
Being prime itself, it is possible to continuously remove digits from left to right,
and remain prime at each stage: 3797, 797, 97, and 7.
Similarly we can work from right to left: 3797, 379, 37, and 3.
Find the sum of the only eleven primes that are both truncatable from left to right and right to left.
NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes.
"""
import time
from itertools import product
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Time taken: {end_time - start_time:.6f} seconds")
return result
return wrapper
def combine_lists(a: list[int], b: list[int | None], c: list[int]) -> list[int]:
"""将三个列表的每个元素组合成数字"""
return [int(f"{x}{y}{z}") for x, y, z in product(a, b, c)]
def is_prime(n: int) -> bool:
"""判断一个数是否为素数"""
if n < 2:
return False
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
return False
return True
def truncate_left(n: int) -> bool:
"""从左到右截断一个数"""
length = len(str(n))
while n > 0:
if not is_prime(n):
return False
n %= 10 ** (length - 1)
length -= 1
return True
def truncate_right(n: int) -> bool:
"""从右到左截断一个数"""
while n > 0:
if not is_prime(n):
return False
n //= 10
return True
def TruncatablePrime() -> list[int]:
begin = [2, 3, 5, 7]
end = [3, 7]
middle = [1, 3, 7, 9]
res = []
for length in range(2, 7):
if length - 2 == 0:
midb = []
else:
midb = product(middle, repeat=length - 2)
midb = [int("".join(map(str, x))) for x in midb]
nums = combine_lists(begin, midb, end)
for num in nums:
if is_prime(num):
if truncate_left(num) and truncate_right(num):
res.append(num)
return res
@timer
def main():
print(sum(TruncatablePrime()))
if __name__ == "__main__":
main()