素数(质数) 是大于 1 的自然数,只能被 1 和它本身整除。
示例:
对每个数 m
,检查是否能被 2
到 m-1
之间的数整除。如果都不能,则是素数。
pythondef is_prime(m):
if m <= 1:
return False
for i in range(2, m):
if m % i == 0:
return False
return True
def count_primes(n):
count = 0
for i in range(2, n+1):
if is_prime(i):
count += 1
return count
效率极低,例如判断 100 是否为素数要检查 98 次,当 n
很大时(如 10⁶),计算会非常慢。
如果 m
能被某个数整除,那么其中一个因数一定小于等于 √m
。例如 16 的因数 4,只需要检查到 4 即可。
pythonimport math
def is_prime(m):
if m <= 1:
return False
if m == 2: # 2 是唯一的偶素数
return True
if m % 2 == 0: # 其他偶数直接排除
return False
sqrt_m = int(math.sqrt(m)) + 1 # 检查到平方根
for i in range(3, sqrt_m, 2): # 只检查奇数
if m % i == 0:
return False
return True
通过“筛子”筛掉非素数,剩下的就是素数:
pythondef count_primes_sieve(n):
if n < 2:
return 0
sieve = [True] * (n+1) # 初始化为全 True
sieve[0] = sieve[1] = False # 0 和 1 不是素数
for i in range(2, int(math.sqrt(n)) + 1):
if sieve[i]: # 如果 i 是素数
sieve[i*i : n+1 : i] = [False] * len(sieve[i*i : n+1 : i]) # 标记 i 的倍数
return sum(sieve) # 统计 True 的数量
时间复杂度为 O(n log log n),处理 n=10^6
仅需几毫秒。
除了 2,所有偶数都不是素数。初始化时直接排除偶数,节省一半空间和时间。
pythondef count_primes_sieve_optimized(n):
if n < 2:
return 0
if n == 2:
return 1
sieve = [True] * (n+1)
sieve[0] = sieve[1] = False
sieve[4::2] = [False] * ((n-4)//2 + 1) # 标记所有偶数(除了2)
sieve[2] = True # 2 是素数
for i in range(3, int(math.sqrt(n)) + 1, 2): # 只检查奇数
if sieve[i]:
sieve[i*i : n+1 : 2*i] = [False] * len(sieve[i*i : n+1 : 2*i]) # 步长设为 2i
return sum(sieve)
方法 | 特点 | 时间复杂度 |
---|---|---|
基础方法 | 简单直观,效率低下 | O(n√n) |
平方根判断法 | 效率提升明显 | O(n√n) |
埃氏筛法 | 快速高效 | O(n log log n) |
优化筛法(跳偶) | 空间与时间更优 | O(n log log n) |
pythonimport time
n = 100000
start = time.time()
print(count_primes_sieve(n))
print("筛法耗时:", time.time() - start)
start = time.time()
print(count_primes(n)) # 基础方法(逐个判断)
print("基础方法耗时:", time.time() - start)
bitarray
)来节省内存。本文作者:Dong
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!