Files
SolutionEuler/solutions/0049.PrimePermutations/euler_49_better.py

107 lines
3.3 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.

"""
The arithmetic sequence, 1487,4817,8147, in which each of the terms increases by 3330,
is unusual in two ways: (i) each of the three terms are prime, and, (ii) each of the
4-digit numbers are permutations of one another.
There are no arithmetic sequences made up of three 1-, 2-, or 3-digit primes, exhibiting this property,
but there is one other 4-digit increasing sequence.
What 12-digit number do you form by concatenating the three terms in this sequence?
"""
import time
from logging import root
from pathlib import Path
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"{func.__name__} time: {elapsed_time:.6f} seconds")
return result
return wrapper
@timer
def solve_ultra_optimized(n: int = 4) -> list[str]:
limit = 10**n
mini_limit = 10 ** (n - 1) + 1
# ========== 1. Bitset 筛法(内存高效) ==========
is_prime = bytearray(b"\x01") * limit
is_prime[0] = is_prime[1] = 0
# 埃氏筛,使用切片赋值加速
for i in range(2, int(limit**0.5) + 1):
if is_prime[i]:
start = i * i
is_prime[start:limit:i] = b"\x00" * ((limit - start - 1) // i + 1)
# ========== 2. 按数字签名分组 ==========
groups = {}
for p in range(mini_limit, limit, 2): # 只遍历奇数4位质数必为奇数
if is_prime[p]:
key = "".join(sorted(str(p)))
groups.setdefault(key, []).append(p)
# ========== 3. 组内搜索利用模18剪枝 ==========
res = []
for key, group in groups.items():
if len(group) < 3:
continue
group.sort()
group_set = set(group) # 用于O(1)成员检查
n = len(group)
for i in range(n):
a = group[i]
for j in range(i + 1, n):
b = group[j]
d = b - a
# 核心数学优化公差必须是18的倍数
# 原因:(1) 排列数字和相同 => 模9同余 => d%9==0
# (2) 质数>2都是奇数 => 奇+偶=奇 => d%2==0
if d % 18 != 0:
continue
c = b + d
# 边界检查利用group有序性提前终止
if c >= limit:
break
# Bitset O(1) 质数检查
if not is_prime[c]:
continue
# 确认第三项在组内(数字签名匹配)
if c in group_set:
res.append(f"{a}-{b}-{c}:{d}")
return res
if __name__ == "__main__":
try:
n = int(input("Search digits (default is 4-digit): ") or "4")
except ValueError:
n = 4
res = solve_ultra_optimized(n)
if lr := len(res) > 10:
head = 10
print(
f"Too much data, only showing the first ten rows. Other data saved in result_{n}_digit.txt."
)
root_path = Path(__file__).parent
with open(f"{root_path}/result_{n}_digit.txt", "w", encoding="utf-8") as f:
f.write("\n".join(res))
else:
head = lr
for x in res[:head]:
print(x)