✨ feat(project-euler):添加第7题和第8题的解决方案
📝 docs(project-euler):为第7题添加详细的埃拉托斯特尼筛法文档
This commit is contained in:
43
solutions/0007.10001stPrime/euler_7.py
Normal file
43
solutions/0007.10001stPrime/euler_7.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
"""
|
||||||
|
By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.
|
||||||
|
What is the 10001st prime number?
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
from math import log
|
||||||
|
|
||||||
|
|
||||||
|
def timer(func):
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
start = time.time()
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
end = time.time()
|
||||||
|
print(f"{func.__name__} took {end - start:.6f} seconds")
|
||||||
|
return result
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def sieve_nth_prime(n: int) -> int | None:
|
||||||
|
if n == 1:
|
||||||
|
return 2
|
||||||
|
# 估算上限:第n个质数约在 n*log(n) 附近
|
||||||
|
limit = int(n * (log(n) + log(log(n)))) + 10 if n > 6 else 20
|
||||||
|
sieve = [True] * limit
|
||||||
|
sieve[0:2] = [False, False] # 0和1不是质数
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for p in range(2, limit):
|
||||||
|
if sieve[p]:
|
||||||
|
count += 1
|
||||||
|
if count == n:
|
||||||
|
return p
|
||||||
|
# 标记倍数
|
||||||
|
sieve[p * p : limit : p] = [False] * ((limit - 1 - p * p) // p + 1)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(sieve_nth_prime(10001))
|
||||||
153
solutions/0007.10001stPrime/readme.md
Normal file
153
solutions/0007.10001stPrime/readme.md
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
# 埃拉托斯特尼筛法
|
||||||
|
|
||||||
|
埃拉托斯特尼筛法(Sieve of Eratosthenes)是最古老、最优雅的质数筛选算法,
|
||||||
|
由古希腊数学家埃拉托斯特尼在公元前3世纪提出。
|
||||||
|
|
||||||
|
### **核心思想**
|
||||||
|
|
||||||
|
**" multiples of primes are composite "**
|
||||||
|
(质数的倍数都是合数)
|
||||||
|
|
||||||
|
从2开始,逐个标记每个质数的所有倍数为非质数,剩下的未标记数就是质数。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **算法步骤**
|
||||||
|
|
||||||
|
**示例:找出 ≤30 的所有质数**
|
||||||
|
|
||||||
|
1. **初始化**:列出 2 到 30 的所有整数
|
||||||
|
```
|
||||||
|
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **筛选过程**:
|
||||||
|
- **p=2**:保留2,标记所有2的倍数(4,6,8...)
|
||||||
|
- **p=3**:下一个未标记的是3,保留3,标记3的倍数(6,9,12...)
|
||||||
|
- **p=5**:下一个未标记的是5,保留5,标记5的倍数(10,15,20,25,30)
|
||||||
|
- **p=7**:7²=49 > 30,停止
|
||||||
|
|
||||||
|
3. **结果**:剩下的未标记数
|
||||||
|
```
|
||||||
|
2 3 5 7 11 13 17 19 23 29
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **关键优化点**
|
||||||
|
|
||||||
|
**只需筛到 √n**:
|
||||||
|
要找出 ≤n 的所有质数,只需检查到 √n 即可。
|
||||||
|
**证明**:任何合数 m ≤ n 必有一个质因数 ≤ √n,否则 m = p₁×p₂ > √n×√n = n,矛盾。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **正确实现(Python)**
|
||||||
|
|
||||||
|
```python
|
||||||
|
def sieve(n):
|
||||||
|
"""返回所有小于等于n的质数"""
|
||||||
|
if n < 2:
|
||||||
|
return []
|
||||||
|
|
||||||
|
sieve = [True] * (n + 1)
|
||||||
|
sieve[0:2] = [False, False] # 0和1不是质数
|
||||||
|
|
||||||
|
for p in range(2, int(n**0.5) + 1):
|
||||||
|
if sieve[p]:
|
||||||
|
# 从p²开始标记,更小的倍数已被前面的质数标记过
|
||||||
|
sieve[p*p:n+1:p] = [False] * ((n - p*p) // p + 1)
|
||||||
|
|
||||||
|
return [i for i, is_prime in enumerate(sieve) if is_prime]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **复杂度分析**
|
||||||
|
|
||||||
|
| 指标 | 复杂度 | 说明 |
|
||||||
|
|------|--------|------|
|
||||||
|
| **时间** | O(n log log n) | 近乎线性,非常高效 |
|
||||||
|
| **空间** | O(n) | 需要布尔数组存储每个数 |
|
||||||
|
|
||||||
|
**推导**:
|
||||||
|
质数p会标记 n/p 个数,总操作量 ≈ n×(1/2 + 1/3 + 1/5 + ... + 1/p_k)
|
||||||
|
根据质数定理,该和式 ≈ n log log n
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **进阶优化技巧**
|
||||||
|
|
||||||
|
1. **仅筛奇数**:偶数除了2都不是质数,内存减半
|
||||||
|
```python
|
||||||
|
sieve = [True] * ((n + 1) // 2)
|
||||||
|
# 索引i对应数字 2*i+1
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **位压缩**:用bit array而非bool,内存再降8倍
|
||||||
|
```python
|
||||||
|
from bitarray import bitarray
|
||||||
|
sieve = bitarray(n + 1)
|
||||||
|
sieve.setall(True)
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **分段筛选**:当n极大(>10⁸)时,分段加载到缓存
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **适用场景**
|
||||||
|
|
||||||
|
✅ **适合**:
|
||||||
|
- 需要一次性生成大量质数
|
||||||
|
- 频繁查询范围内的质数
|
||||||
|
- n在百万到千万级别
|
||||||
|
|
||||||
|
❌ **不适合**:
|
||||||
|
- 只需判断单个数是否为质数
|
||||||
|
- n极大(>10¹⁰)且内存有限
|
||||||
|
- 仅需要第n个质数而非全部
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
分段筛法:当n极大(>10⁸)时,分段加载到缓存,减少内存占用。
|
||||||
|
|
||||||
|
```python
|
||||||
|
def segmented_nth_prime(n, segment_size=100000):
|
||||||
|
# 先用小筛法生成基础质数
|
||||||
|
base_limit = int((n * (log(n) + log(log(n))))**0.5) + 1
|
||||||
|
base_primes = sieve_primes(base_limit)
|
||||||
|
|
||||||
|
count = len(base_primes)
|
||||||
|
if count >= n:
|
||||||
|
return base_primes[n-1]
|
||||||
|
|
||||||
|
low = base_limit
|
||||||
|
while True:
|
||||||
|
high = low + segment_size
|
||||||
|
segment = [True] * segment_size
|
||||||
|
|
||||||
|
for p in base_primes:
|
||||||
|
start = ((low + p - 1) // p) * p
|
||||||
|
if start < p * p:
|
||||||
|
start = p * p
|
||||||
|
for multiple in range(start, high, p):
|
||||||
|
segment[multiple - low] = False
|
||||||
|
|
||||||
|
for i, is_p in enumerate(segment):
|
||||||
|
if is_p and i + low > 1:
|
||||||
|
count += 1
|
||||||
|
if count == n:
|
||||||
|
return i + low
|
||||||
|
low = high
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
生产环境推荐使用 pyprimesieve 库
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 生产环境推荐使用 pyprimesieve 库
|
||||||
|
# pip install pyprimesieve
|
||||||
|
from pyprimesieve import nth_prime
|
||||||
|
print(nth_prime(10**7))
|
||||||
|
```
|
||||||
79
solutions/0008.LargestProduct/eular_8.py
Normal file
79
solutions/0008.LargestProduct/eular_8.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
"""
|
||||||
|
73167176531330624919225119674426574742355349194934
|
||||||
|
96983520312774506326239578318016984801869478851843
|
||||||
|
85861560789112949495459501737958331952853208805511
|
||||||
|
12540698747158523863050715693290963295227443043557
|
||||||
|
66896648950445244523161731856403098711121722383113
|
||||||
|
62229893423380308135336276614282806444486645238749
|
||||||
|
30358907296290491560440772390713810515859307960866
|
||||||
|
70172427121883998797908792274921901699720888093776
|
||||||
|
65727333001053367881220235421809751254540594752243
|
||||||
|
52584907711670556013604839586446706324415722155397
|
||||||
|
53697817977846174064955149290862569321978468622482
|
||||||
|
83972241375657056057490261407972968652414535100474
|
||||||
|
82166370484403199890008895243450658541227588666881
|
||||||
|
16427171479924442928230863465674813919123162824586
|
||||||
|
17866458359124566529476545682848912883142607690042
|
||||||
|
24219022671055626321111109370544217506941658960408
|
||||||
|
07198403850962455444362981230987879927244284909188
|
||||||
|
84580156166097919133875499200524063689912560717606
|
||||||
|
05886116467109405077541002256983155200055935729725
|
||||||
|
71636269561882670428252483600823257530420752963450
|
||||||
|
|
||||||
|
Find the thirteen adjacent digits in the 1000-digit number that have the greatest product. What is the value of this product?
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
|
||||||
|
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 to run.")
|
||||||
|
return result
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def largest_product_in_series(series: str, n: int) -> int:
|
||||||
|
if n <= 0 or n > len(series):
|
||||||
|
return 0
|
||||||
|
# 转换为整数列表
|
||||||
|
# 移除所有空格
|
||||||
|
series = series.replace("\n", "")
|
||||||
|
series = series.replace(" ", "")
|
||||||
|
digits = [int(x) for x in series]
|
||||||
|
max_product = 0
|
||||||
|
# 遍历所有可能的子序列
|
||||||
|
for i in range(len(digits) - n + 1):
|
||||||
|
product = reduce(lambda x, y: x * y, digits[i : i + n])
|
||||||
|
max_product = max(max_product, product)
|
||||||
|
return max_product
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
txt = """73167176531330624919225119674426574742355349194934
|
||||||
|
96983520312774506326239578318016984801869478851843
|
||||||
|
85861560789112949495459501737958331952853208805511
|
||||||
|
12540698747158523863050715693290963295227443043557
|
||||||
|
66896648950445244523161731856403098711121722383113
|
||||||
|
62229893423380308135336276614282806444486645238749
|
||||||
|
30358907296290491560440772390713810515859307960866
|
||||||
|
70172427121883998797908792274921901699720888093776
|
||||||
|
65727333001053367881220235421809751254540594752243
|
||||||
|
52584907711670556013604839586446706324415722155397
|
||||||
|
53697817977846174064955149290862569321978468622482
|
||||||
|
83972241375657056057490261407972968652414535100474
|
||||||
|
82166370484403199890008895243450658541227588666881
|
||||||
|
16427171479924442928230863465674813919123162824586
|
||||||
|
17866458359124566529476545682848912883142607690042
|
||||||
|
24219022671055626321111109370544217506941658960408
|
||||||
|
07198403850962455444362981230987879927244284909188
|
||||||
|
84580156166097919133875499200524063689912560717606
|
||||||
|
05886116467109405077541002256983155200055935729725
|
||||||
|
71636269561882670428252483600823257530420752963450"""
|
||||||
|
print(largest_product_in_series(txt, 13))
|
||||||
Reference in New Issue
Block a user