feat(0043.SubStrDivisibility):添加欧拉项目第43题解决方案

📝 docs(0043.SubStrDivisibility):添加解题思路说明文档
This commit is contained in:
2026-01-15 14:43:29 +08:00
parent 0c344afe01
commit af1cb88018
2 changed files with 118 additions and 0 deletions

View File

@@ -0,0 +1,110 @@
"""
The number, 1406357289, is a 0 to 9 pandigital number because it is made up of each of the digits 0 to 9
in some order, but it also has a rather interesting sub-string divisibility property.
Let d_1 be the 1st digit, d_2 be the 2nd digit, and so on. In this way, we note the following:
d_2d_3d_4 is divisible by 2
d_3d_4d_5 is divisible by 3
d_4d_5d_6 is divisible by 5
d_5d_6d_7 is divisible by 7
d_6d_7d_8 is divisible by 11
d_7d_8d_9 is divisible by 13
d_8d_9d_10 is divisible by 17
Find the sum of all 0 to 9 pandigital numbers with this property.
"""
import time
from itertools import permutations
from tkinter.constants import TOP
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
print(f"Execution time: {end_time - start_time} seconds")
return result
return wrapper
def get_all_numbers() -> list[int]:
ori = list(permutations(list(range(10))))
res = []
for x in ori:
if x[3] % 2 != 0:
continue
if x[5] not in [0, 5]:
continue
for i, d in enumerate([2, 3, 5, 7, 11, 13, 17]):
if int("".join(map(str, x[i + 1 : i + 4]))) % d != 0:
break
else:
res.append(int("".join(map(str, x))))
return res
def optimized_solve() -> tuple[int, list[int]]:
total = 0
# 从最后三位开始这些必须能被17整除
candidates = []
for n in range(102, 1000, 17):
s = str(n).zfill(3)
if len(set(s)) == 3: # 三位数字必须不同
candidates.append(s)
# 逐步向前添加数字,检查约束
for i, prime in enumerate([13, 11, 7, 5, 3, 2]):
new_candidates = []
for cand in candidates:
# 获取当前已使用的数字
used_digits = set(cand)
# 尝试添加一个新数字在最前面
for d in "0123456789":
if d not in used_digits:
# 新形成的三位数
new_triplet = d + cand[:2]
# 检查是否能被对应的质数整除
if int(new_triplet) % prime == 0:
new_candidates.append(d + cand)
candidates = new_candidates
# 现在candidates中包含的是d_2到d_109位数字
# 我们需要添加第一个数字d_1
final_numbers = []
for cand in candidates:
used_digits = set(cand)
# 找出缺失的那个数字
for d in "0123456789":
if d not in used_digits and d != "0": # d_1不能为0
num = d + cand
# 验证这是一个0-9的pandigital数
if len(set(num)) == 10:
final_numbers.append(num)
# 计算总和
total = sum(int(num) for num in final_numbers)
return total, [int(num) for num in final_numbers]
@timer
def main():
numbers = get_all_numbers()
print(sum(numbers))
@timer
def main_op():
total, _ = optimized_solve()
print(total)
if __name__ == "__main__":
main()
main_op()

View File

@@ -0,0 +1,8 @@
# 简单思路说明
使用简单方式循环构建进行计算,刨除最简单的特征外,最多减少一半计算时间。这是从前往后进行计算的时候。
但是从后往前就要快速多了。最后三位是形式确认的17的倍数所以可以减少更多的计算次数
一千以内的17倍数只有不足60个相应的递归到下一位数所需计算次数也不会慢更多。
从最小可确认开始思考这种具有递归特征的问题,可能更容易进行计算求解。