51题完成解决
This commit is contained in:
194
solutions/0051.PrimeDigitReplace/euler_51.py
Normal file
194
solutions/0051.PrimeDigitReplace/euler_51.py
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
"""
|
||||||
|
By replacing the 1st digit of the 2-digit number *3,
|
||||||
|
it turns out that six of the nine possible values: 13, 23, 43, 53, 73, and 83, are all prime.
|
||||||
|
|
||||||
|
By replacing the 3rd and 4th digits of 56**3 with the same digit,
|
||||||
|
this 5-digit number is the first example having seven primes among the ten generated numbers,
|
||||||
|
yielding the family: 56003, 56113, 56333, 56443, 56663, 56773, and 56993.
|
||||||
|
Consequently 56003, being the first member of this family, is the smallest prime with this property.
|
||||||
|
|
||||||
|
Find the smallest prime which,
|
||||||
|
by replacing part of the number (not necessarily adjacent digits) with the same digit,
|
||||||
|
is part of an eight prime value family.
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
*.000*.、*.111*.、*.222*.、*.333*.、*.444*.、*.555*.、*.666*.、*.777*.、*.888*.、*.999*.
|
||||||
|
|
||||||
|
数字的形式就是这样,最多十个数,那么,就是要在质数序列上搜索这样的数列:
|
||||||
|
|
||||||
|
1. 用欧拉筛生成质数表(上限约100万足够)
|
||||||
|
2. 对每个质数p:
|
||||||
|
a. 检查是否有≥3个相同数字,且该数字∈{0,1,2}
|
||||||
|
b. 生成所有C(n,3)种3位替换组合
|
||||||
|
c. 对每种组合,用0-9替换,统计质数个数
|
||||||
|
d. 若得到8个质数,返回p(首个即为答案)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import itertools
|
||||||
|
import time
|
||||||
|
from collections import Counter
|
||||||
|
from math import isqrt
|
||||||
|
|
||||||
|
from bitarray import bitarray
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def replace_digit(
|
||||||
|
number: str | int,
|
||||||
|
target_digit: str | int,
|
||||||
|
replace_count: int = 3,
|
||||||
|
replacement_digit: str | int = "0123456789",
|
||||||
|
return_positions: bool = False,
|
||||||
|
) -> list[str] | list[tuple]:
|
||||||
|
"""
|
||||||
|
使用单个替换数字,替换指定数量的目标数字
|
||||||
|
|
||||||
|
参数:
|
||||||
|
number: 输入的数字(字符串或整数)
|
||||||
|
target_digit: 要被替换的目标数字(如 '1')
|
||||||
|
replace_count: 要替换的数量(必须 <= 目标数字出现的次数)
|
||||||
|
replacement_digit: 用于替换的数字(单个字符)
|
||||||
|
return_positions: 是否同时返回被替换的位置信息
|
||||||
|
|
||||||
|
返回:
|
||||||
|
如果return_positions为False,返回替换后的数字列表
|
||||||
|
如果return_positions为True,返回[(替换后的数字, 被替换的位置), ...]
|
||||||
|
"""
|
||||||
|
# 转换为字符串处理
|
||||||
|
num_str = str(number)
|
||||||
|
target = str(target_digit)
|
||||||
|
replacement = str(replacement_digit)
|
||||||
|
|
||||||
|
# 找出所有目标数字的位置
|
||||||
|
target_positions = [i for i, digit in enumerate(num_str) if digit == target]
|
||||||
|
|
||||||
|
# 检查是否有足够的目标数字
|
||||||
|
if len(target_positions) < replace_count:
|
||||||
|
return [
|
||||||
|
f"错误:目标数字 '{target}' 只出现了 {len(target_positions)} 次,少于要替换的数量 {replace_count}"
|
||||||
|
]
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
# 遍历所有可能的要替换的位置组合
|
||||||
|
for positions in itertools.combinations(target_positions, replace_count):
|
||||||
|
# 创建新数字的列表
|
||||||
|
num_list = list(num_str)
|
||||||
|
|
||||||
|
# 替换指定位置
|
||||||
|
for pos in positions:
|
||||||
|
num_list[pos] = replacement
|
||||||
|
|
||||||
|
new_number = "".join(num_list)
|
||||||
|
|
||||||
|
if return_positions:
|
||||||
|
results.append((new_number, positions))
|
||||||
|
else:
|
||||||
|
results.append(new_number)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def replace_muldigits(
|
||||||
|
number: str | int,
|
||||||
|
target_digit: str | int,
|
||||||
|
replace_count: int = 3,
|
||||||
|
replacement_digits: str | list[str] = "0123456789",
|
||||||
|
return_positions: bool = False,
|
||||||
|
) -> list:
|
||||||
|
"""
|
||||||
|
使用多个替换数字,每个数字单独进行替换
|
||||||
|
|
||||||
|
参数:
|
||||||
|
number: 输入的数字
|
||||||
|
target_digit: 目标数字
|
||||||
|
replace_count: 要替换的数量
|
||||||
|
replacement_digits: 多个替换数字(字符串或列表)
|
||||||
|
return_positions: 是否返回位置信息
|
||||||
|
|
||||||
|
返回:
|
||||||
|
字典,键为替换数字,值为对应的结果列表
|
||||||
|
"""
|
||||||
|
# 转换替换数字为列表
|
||||||
|
if isinstance(replacement_digits, str):
|
||||||
|
replacement_list = list(replacement_digits)
|
||||||
|
else:
|
||||||
|
replacement_list = replacement_digits
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
|
||||||
|
for rep_digit in replacement_list:
|
||||||
|
results[rep_digit] = replace_digit(
|
||||||
|
number, target_digit, replace_count, rep_digit, return_positions
|
||||||
|
)
|
||||||
|
|
||||||
|
results = list(results.values())
|
||||||
|
res = [[] for _ in range(len(results[0]))]
|
||||||
|
for r in results:
|
||||||
|
for i, val in enumerate(r):
|
||||||
|
if val[0] != "0":
|
||||||
|
res[i].append(int(val))
|
||||||
|
|
||||||
|
return [sorted(list(set(val))) for val in res]
|
||||||
|
|
||||||
|
|
||||||
|
def primes_list(limit: int = 10**8) -> list[int]:
|
||||||
|
is_prime = bitarray(limit + 1)
|
||||||
|
is_prime.setall(True)
|
||||||
|
is_prime[:2] = False # 0和1不是素数
|
||||||
|
|
||||||
|
# 只需筛到 sqrt(n)
|
||||||
|
imax = isqrt(limit) + 1
|
||||||
|
|
||||||
|
for i in range(2, imax):
|
||||||
|
if is_prime[i]:
|
||||||
|
# 步长i,从i*i开始(小于i*i的已被更小的素数筛过)
|
||||||
|
is_prime[i * i : limit + 1 : i] = False
|
||||||
|
|
||||||
|
return [i for i, isp in enumerate(is_prime) if isp]
|
||||||
|
|
||||||
|
|
||||||
|
def have_n_primes(primes: list[int], target: list[int]) -> int:
|
||||||
|
count = 0
|
||||||
|
for n in target:
|
||||||
|
if n in primes:
|
||||||
|
count += 1
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def solve() -> list[int]:
|
||||||
|
primes = primes_list()
|
||||||
|
for p in primes:
|
||||||
|
if p < 1000:
|
||||||
|
continue
|
||||||
|
digits = [int(d) for d in str(p)]
|
||||||
|
digit_counts = Counter(digits)
|
||||||
|
if max(digit_counts.values()) < 3:
|
||||||
|
continue
|
||||||
|
digs = [k for k, v in digit_counts.items() if v >= 3 and k in [0, 1, 2]]
|
||||||
|
for dig in digs:
|
||||||
|
testList = replace_muldigits(p, dig)
|
||||||
|
for xList in testList:
|
||||||
|
if have_n_primes(primes, xList) == 8:
|
||||||
|
return [x for x in xList if x in primes]
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
result = solve()
|
||||||
|
print(result)
|
||||||
105
solutions/0051.PrimeDigitReplace/euler_51_better.py
Normal file
105
solutions/0051.PrimeDigitReplace/euler_51_better.py
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
"""
|
||||||
|
By replacing the 1st digit of the 2-digit number *3,
|
||||||
|
it turns out that six of the nine possible values: 13, 23, 43, 53, 73, and 83, are all prime.
|
||||||
|
|
||||||
|
By replacing the 3rd and 4th digits of 56**3 with the same digit,
|
||||||
|
this 5-digit number is the first example having seven primes among the ten generated numbers,
|
||||||
|
yielding the family: 56003, 56113, 56333, 56443, 56663, 56773, and 56993.
|
||||||
|
Consequently 56003, being the first member of this family, is the smallest prime with this property.
|
||||||
|
|
||||||
|
Find the smallest prime which,
|
||||||
|
by replacing part of the number (not necessarily adjacent digits) with the same digit,
|
||||||
|
is part of an eight prime value family.
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
*.000*.、*.111*.、*.222*.、*.333*.、*.444*.、*.555*.、*.666*.、*.777*.、*.888*.、*.999*.
|
||||||
|
|
||||||
|
数字的形式就是这样,最多十个数,那么,就是要在质数序列上搜索这样的数列:
|
||||||
|
|
||||||
|
1. 用欧拉筛生成质数表(上限约100万足够)
|
||||||
|
2. 对每个质数p:
|
||||||
|
a. 检查是否有≥3个相同数字,且该数字∈{0,1,2}
|
||||||
|
b. 生成所有C(n,3)种3位替换组合
|
||||||
|
c. 对每种组合,用0-9替换,统计质数个数
|
||||||
|
d. 若得到8个质数,返回p(首个即为答案)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
from itertools import combinations
|
||||||
|
from math import isqrt
|
||||||
|
|
||||||
|
from bitarray import bitarray
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def primes_list(limit: int = 10**8) -> set[int]:
|
||||||
|
is_prime = bitarray(limit + 1)
|
||||||
|
is_prime.setall(True)
|
||||||
|
is_prime[:2] = False # 0和1不是素数
|
||||||
|
|
||||||
|
# 只需筛到 sqrt(n)
|
||||||
|
imax = isqrt(limit) + 1
|
||||||
|
|
||||||
|
for i in range(2, imax):
|
||||||
|
if is_prime[i]:
|
||||||
|
# 步长i,从i*i开始(小于i*i的已被更小的素数筛过)
|
||||||
|
is_prime[i * i : limit + 1 : i] = False
|
||||||
|
|
||||||
|
return {i for i, isp in enumerate(is_prime) if isp}
|
||||||
|
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def solve() -> list[int]:
|
||||||
|
primes = primes_list(10**6)
|
||||||
|
|
||||||
|
# 遍历所有可能的模式
|
||||||
|
for prime in sorted(primes):
|
||||||
|
if prime < 1000: # 从4位数开始
|
||||||
|
continue
|
||||||
|
|
||||||
|
s = str(prime)
|
||||||
|
|
||||||
|
# 检查每个出现3次或以上的数字
|
||||||
|
for d in set(s):
|
||||||
|
positions = [i for i, c in enumerate(s) if c == d]
|
||||||
|
if len(positions) < 3:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 尝试替换3个位置
|
||||||
|
for combo in combinations(positions, 3):
|
||||||
|
if 0 in combo and d == "0":
|
||||||
|
continue
|
||||||
|
|
||||||
|
family = []
|
||||||
|
for new_d in "0123456789":
|
||||||
|
new_num_str = "".join(
|
||||||
|
new_d if i in combo else c for i, c in enumerate(s)
|
||||||
|
)
|
||||||
|
new_num = int(new_num_str)
|
||||||
|
|
||||||
|
# 确保长度相同且是素数
|
||||||
|
if len(str(new_num)) == len(s) and new_num in primes:
|
||||||
|
family.append(new_num)
|
||||||
|
|
||||||
|
if len(family) == 8:
|
||||||
|
return sorted(family)
|
||||||
|
|
||||||
|
return [-1]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
result = solve()
|
||||||
|
print(result)
|
||||||
Reference in New Issue
Block a user