Files
SolutionEuler/solutions/0035.CircularPrimes/euler_35_better.py

81 lines
2.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} took {end_time - start_time:.6f} seconds")
return result
return wrapper
# ---------- 1. PRIMES ----------
MAX = 1_000_000
is_p = bytearray(b"\1") * MAX # 1 表示素数0 表示合数(与原来相反,方便理解)
is_p[0] = is_p[1] = 0 # 0和1不是素数
# 优化:使用标准埃拉托斯特尼筛法
for p in range(2, int(MAX**0.5) + 1):
if is_p[p]:
is_p[p * p : MAX : p] = b"\0" * ((MAX - p * p - 1) // p + 1)
# ---------- 2. SCROLLING ----------
def rotations(n: int) -> list[int]:
"""返回 n 的所有旋转(数学移位版,无字符串开销)"""
if n < 10:
return [n]
s = str(n)
k = len(s)
res = []
for i in range(k):
# 使用切片旋转,避免重复计算
rotated = int(s[i:] + s[:i])
res.append(rotated)
return res
# ---------- 3. MAIN ----------
@timer
def main(limit: int = MAX) -> int:
# 预过滤:只要含 0,2,4,5,6,8 就可以跳过除了2和5本身
bad_digits = set("024568")
total = 0
counted = set() # 用于去重,避免重复计数
for p in range(2, limit):
if is_p[p]: # p是素数
# 快速数字过滤2和5是特例
if p != 2 and p != 5:
s = str(p)
if not bad_digits.isdisjoint(s):
continue
# 如果已经统计过,跳过
if p in counted:
continue
# 检查所有旋转
rs = rotations(p)
# 检查所有旋转数是否都是素数
valid = True
for r in rs:
if r >= limit or not is_p[r]:
valid = False
break
if valid:
# 如果是循环素数,统计并标记已计数
total += len(set(rs)) # 使用set避免重复旋转
counted.update(rs)
return total
if __name__ == "__main__":
print(f"循环素数数量: {main()}")