chore: update 2026-04-22
This commit is contained in:
@@ -21,3 +21,8 @@
|
|||||||
|
|
||||||
为了便于管理和使用,简单创建了一个脚本。
|
为了便于管理和使用,简单创建了一个脚本。
|
||||||
这个脚本只有三个主要功能,一个是创建新问题的文件,一个是列出已创建问题,还有一个是运行指定问题的python解法。
|
这个脚本只有三个主要功能,一个是创建新问题的文件,一个是列出已创建问题,还有一个是运行指定问题的python解法。
|
||||||
|
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
优化了装饰器Banchmark运行时间的计算函数,现在可以重复运行并计算平均运行时间。(55题(含)之后开始使用。)
|
||||||
|
|||||||
50
main.py
50
main.py
@@ -22,17 +22,49 @@ def add_newproblem(num: int, name: str | None = None) -> None:
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
import time
|
import time
|
||||||
|
from functools import wraps
|
||||||
|
from typing import Any, Callable, TypeVar
|
||||||
|
|
||||||
|
F = TypeVar("F", bound=Callable[..., Any])
|
||||||
|
|
||||||
|
|
||||||
def timer(func):
|
def benchmark(repeat: int = 1) -> Callable[[F], F]:
|
||||||
def wrapper(*args, **kwargs):
|
'''
|
||||||
start_time = time.time()
|
重复运行目标函数并计算平均耗时。
|
||||||
result = func(*args, **kwargs)
|
|
||||||
end_time = time.time()
|
平均耗时会被存储在 wrapper.avg_time 和 wrapper.total_time 中,
|
||||||
elapsed_time = end_time - start_time
|
同时会打印到控制台。函数的返回值不受影响。
|
||||||
print(f"{func.__name__} time: {elapsed_time:.6f} seconds")
|
'''
|
||||||
return result
|
if repeat < 1:
|
||||||
return wrapper
|
raise ValueError("repeat 必须 >= 1")
|
||||||
|
|
||||||
|
def decorator(func: F) -> F:
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
||||||
|
total = 0.0
|
||||||
|
result = None
|
||||||
|
|
||||||
|
for _ in range(repeat):
|
||||||
|
start = time.perf_counter()
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
end = time.perf_counter()
|
||||||
|
total += end - start
|
||||||
|
|
||||||
|
wrapper.avg_time = total / repeat # type: ignore[attr-defined]
|
||||||
|
wrapper.total_time = total # type: ignore[attr-defined]
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"[Benchmark] {func.__name__} | 重复 {repeat} 次 | "
|
||||||
|
f"平均: {wrapper.avg_time:.6f}s | 总计: {wrapper.total_time:.6f}s" # type: ignore[attr-defined]
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
# 初始化属性,避免调用前访问报错
|
||||||
|
wrapper.avg_time = 0.0 # type: ignore[attr-defined]
|
||||||
|
wrapper.total_time = 0.0 # type: ignore[attr-defined]
|
||||||
|
return wrapper # type: ignore[return-value]
|
||||||
|
|
||||||
|
return decorator
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
98
solutions/0055.LychrelNum/euler_55.py
Normal file
98
solutions/0055.LychrelNum/euler_55.py
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
"""
|
||||||
|
If we take 47, reverse and add, 47 + 74 = 121, which is palindromic.
|
||||||
|
|
||||||
|
Not all numbers produce palindromes so quickly. For example,
|
||||||
|
349 + 943 = 1292
|
||||||
|
1292 + 2921 = 4213
|
||||||
|
4213 + 3124 = 7337
|
||||||
|
That is, 349 took three iterations to arrive at a palindrome.
|
||||||
|
|
||||||
|
Although no one has proved it yet, it is thought that some numbers, like 196,
|
||||||
|
never produce a palindrome. A number that never forms a palindrome through the
|
||||||
|
reverse and add process is called a Lychrel number. Due to the theoretical nature
|
||||||
|
of these numbers, and for the purpose of this problem, we shall assume that
|
||||||
|
a number is Lychrel until proven otherwise. In addition you are given that for
|
||||||
|
every number below ten-thousand, it will either (i) become a palindrome
|
||||||
|
in less than fifty iterations, or, (ii) no one, with all the computing power that exists,
|
||||||
|
has managed so far to map it to a palindrome. In fact, 10677 is the first number to
|
||||||
|
be shown to require over fifty iterations before producing a palindrome:
|
||||||
|
4668731596684224866951378664 (53 iterations, 28-digits).
|
||||||
|
|
||||||
|
Surprisingly, there are palindromic numbers that are themselves Lychrel numbers;
|
||||||
|
the first example is 4994.
|
||||||
|
|
||||||
|
How many Lychrel numbers are there below ten-thousand?
|
||||||
|
|
||||||
|
NOTE: Wording was modified slightly on 24 April 2007 to emphasise the theoretical nature of Lychrel numbers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
from functools import wraps
|
||||||
|
from typing import Any, Callable, TypeVar
|
||||||
|
|
||||||
|
F = TypeVar("F", bound=Callable[..., Any])
|
||||||
|
|
||||||
|
|
||||||
|
def benchmark(repeat: int = 1) -> Callable[[F], F]:
|
||||||
|
"""
|
||||||
|
重复运行目标函数并计算平均耗时。
|
||||||
|
|
||||||
|
平均耗时会被存储在 wrapper.avg_time 和 wrapper.total_time 中,
|
||||||
|
同时会打印到控制台。函数的返回值不受影响。
|
||||||
|
"""
|
||||||
|
if repeat < 1:
|
||||||
|
raise ValueError("repeat 必须 >= 1")
|
||||||
|
|
||||||
|
def decorator(func: F) -> F:
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
||||||
|
total = 0.0
|
||||||
|
result = None
|
||||||
|
|
||||||
|
for _ in range(repeat):
|
||||||
|
start = time.perf_counter()
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
end = time.perf_counter()
|
||||||
|
total += end - start
|
||||||
|
|
||||||
|
wrapper.avg_time = total / repeat # type: ignore[attr-defined]
|
||||||
|
wrapper.total_time = total # type: ignore[attr-defined]
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"[Benchmark] {func.__name__} | 重复 {repeat} 次 | "
|
||||||
|
f"平均: {wrapper.avg_time:.6f}s | 总计: {wrapper.total_time:.6f}s" # type: ignore[attr-defined]
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
# 初始化属性,避免调用前访问报错
|
||||||
|
wrapper.avg_time = 0.0 # type: ignore[attr-defined]
|
||||||
|
wrapper.total_time = 0.0 # type: ignore[attr-defined]
|
||||||
|
return wrapper # type: ignore[return-value]
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def is_palindrome(n):
|
||||||
|
return str(n) == str(n)[::-1]
|
||||||
|
|
||||||
|
|
||||||
|
def is_lychrel(n, max_iterations=50):
|
||||||
|
for _ in range(max_iterations):
|
||||||
|
n += int(str(n)[::-1])
|
||||||
|
if is_palindrome(n):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@benchmark(repeat=15)
|
||||||
|
def count_lychrel_numbers(limit):
|
||||||
|
count = 0
|
||||||
|
for n in range(1, limit + 1):
|
||||||
|
if is_lychrel(n):
|
||||||
|
count += 1
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
result = count_lychrel_numbers(10000)
|
||||||
|
print(f"Number of Lychrel numbers below 10,000: {result}")
|
||||||
112
solutions/0055.LychrelNum/euler_55_bit.py
Normal file
112
solutions/0055.LychrelNum/euler_55_bit.py
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
"""
|
||||||
|
If we take 47, reverse and add, 47 + 74 = 121, which is palindromic.
|
||||||
|
|
||||||
|
Not all numbers produce palindromes so quickly. For example,
|
||||||
|
349 + 943 = 1292
|
||||||
|
1292 + 2921 = 4213
|
||||||
|
4213 + 3124 = 7337
|
||||||
|
That is, 349 took three iterations to arrive at a palindrome.
|
||||||
|
|
||||||
|
Although no one has proved it yet, it is thought that some numbers, like 196,
|
||||||
|
never produce a palindrome. A number that never forms a palindrome through the
|
||||||
|
reverse and add process is called a Lychrel number. Due to the theoretical nature
|
||||||
|
of these numbers, and for the purpose of this problem, we shall assume that
|
||||||
|
a number is Lychrel until proven otherwise. In addition you are given that for
|
||||||
|
every number below ten-thousand, it will either (i) become a palindrome
|
||||||
|
in less than fifty iterations, or, (ii) no one, with all the computing power that exists,
|
||||||
|
has managed so far to map it to a palindrome. In fact, 10677 is the first number to
|
||||||
|
be shown to require over fifty iterations before producing a palindrome:
|
||||||
|
4668731596684224866951378664 (53 iterations, 28-digits).
|
||||||
|
|
||||||
|
Surprisingly, there are palindromic numbers that are themselves Lychrel numbers;
|
||||||
|
the first example is 4994.
|
||||||
|
|
||||||
|
How many Lychrel numbers are there below ten-thousand?
|
||||||
|
|
||||||
|
NOTE: Wording was modified slightly on 24 April 2007 to emphasise the theoretical nature of Lychrel numbers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
from functools import wraps
|
||||||
|
from typing import Any, Callable, TypeVar
|
||||||
|
|
||||||
|
from bitarray import bitarray
|
||||||
|
|
||||||
|
F = TypeVar("F", bound=Callable[..., Any])
|
||||||
|
|
||||||
|
|
||||||
|
def benchmark(repeat: int = 1) -> Callable[[F], F]:
|
||||||
|
"""
|
||||||
|
重复运行目标函数并计算平均耗时。
|
||||||
|
|
||||||
|
平均耗时会被存储在 wrapper.avg_time 和 wrapper.total_time 中,
|
||||||
|
同时会打印到控制台。函数的返回值不受影响。
|
||||||
|
"""
|
||||||
|
if repeat < 1:
|
||||||
|
raise ValueError("repeat 必须 >= 1")
|
||||||
|
|
||||||
|
def decorator(func: F) -> F:
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
||||||
|
total = 0.0
|
||||||
|
result = None
|
||||||
|
|
||||||
|
for _ in range(repeat):
|
||||||
|
start = time.perf_counter()
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
end = time.perf_counter()
|
||||||
|
total += end - start
|
||||||
|
|
||||||
|
wrapper.avg_time = total / repeat # type: ignore[attr-defined]
|
||||||
|
wrapper.total_time = total # type: ignore[attr-defined]
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"[Benchmark] {func.__name__} | 重复 {repeat} 次 | "
|
||||||
|
f"平均: {wrapper.avg_time:.6f}s | 总计: {wrapper.total_time:.6f}s" # type: ignore[attr-defined]
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
# 初始化属性,避免调用前访问报错
|
||||||
|
wrapper.avg_time = 0.0 # type: ignore[attr-defined]
|
||||||
|
wrapper.total_time = 0.0 # type: ignore[attr-defined]
|
||||||
|
return wrapper # type: ignore[return-value]
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def reverse_int(n: int) -> int:
|
||||||
|
return int(str(n)[::-1])
|
||||||
|
|
||||||
|
|
||||||
|
@benchmark(repeat=15)
|
||||||
|
def count_lychrel_numbers(limit: int = 10000, max_iter: int = 50) -> int:
|
||||||
|
is_not_lychrel = bitarray(limit + 1)
|
||||||
|
is_not_lychrel.setall(0)
|
||||||
|
is_not_lychrel[0] = 1
|
||||||
|
|
||||||
|
for i in range(1, limit + 1):
|
||||||
|
if is_not_lychrel[i]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
n = i
|
||||||
|
chain = [n]
|
||||||
|
|
||||||
|
for _ in range(max_iter):
|
||||||
|
n += reverse_int(n)
|
||||||
|
|
||||||
|
# 检查是否形成回文
|
||||||
|
if n == reverse_int(n):
|
||||||
|
for num in chain:
|
||||||
|
if num > limit:
|
||||||
|
break
|
||||||
|
is_not_lychrel[num] = 1
|
||||||
|
break
|
||||||
|
|
||||||
|
chain.append(n)
|
||||||
|
|
||||||
|
return is_not_lychrel.count(0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
result = count_lychrel_numbers(10000)
|
||||||
|
print(f"Number of Lychrel numbers below 10,000: {result}")
|
||||||
3
solutions/0055.LychrelNum/readme.md
Normal file
3
solutions/0055.LychrelNum/readme.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
硬算比反馈记录快?
|
||||||
|
在这个问题上,由于数字逆序相加这个特性,造成数字快速增长,可能很多中间过程都在计算目标之外,
|
||||||
|
所以记录并未减少实际计算时间。
|
||||||
Reference in New Issue
Block a user