问题
质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。那么给定一个非负整数n,判断小于n的质数一共有多少个?
方法一,枚举
根据定义,在[1,n-1]区间内遍历,看看是否有能够整除n的因数出现。
def isPrime(num):
for i in range(2, num):
if num % i == 0:
return False
return True
随后,对于区间内的每个n都进行上述判断。
def CountPrime(n):
ans = 0
for num in range(2, n):
ans += isPrime(num)
return ans
时间复杂度 ,空间复杂度
方法二,枚举+数学优化
注意到,因数都是成对出现的,比如8能被2整除,那么肯定也能被4整除,并且一个数的最大因数不会超过sqrt(n),因此我们只需遍历[2, sqrt(n)]区间内的数,来判断n是不是质数。
def isPrime(num):
for i in range(2, int(sqrt(num)+1)):
if num % i == 0:
return False
return True
时间复杂度 ,空间复杂度 。
方法三,枚举+数学优化+剪枝
注意到任何大于等于5的质数都会出现在6的倍数左右2侧。
证明:
对于6i,其会被6整除;对于6i+2,其会被2整除;对于6i+3,其会被3整除;对于6i+4,其会被2整除。
因此,我们可以每隔六个数来判断该数是否是质数。
def CountPrime(n):
if n <= 6:
ans = 0
for i in range(n):
if n == 2 or n == 3 or n == 5:
ans += 1
return ans
ans = 2
for num in range(6, n+1, 6):
ans += isPrime(num-1) + (isPrime(num+1) if num+1 < n else 0)
return ans
时间复杂度 ,空间复杂度 ,但是相比于方法二省去了很多不必要的判断,总体上优于方法二。
方法四,埃拉托斯特尼筛法
给出要筛数值的范围n,找出 以内的素数 。先用2去筛,即把2留下,把2的倍数剔除掉;再用下一个素数,也就是3筛,把3留下,把3的倍数剔除掉;接下去用下一个素数5筛,把5留下,把5的倍数剔除掉;不断重复下去…。
from collections import Counter
def CountPrime(n):
Prime_Filter = [i for i in range(2, int(sqrt(n)+1)) if isPrime(i)]
all_number = [True for i in range(n)]
all_number[0] = False
for prime in Prime_Filter:
for j in range(prime*prime, n+1, prime):
all_number[j-1] = False
# print([index+1 for index,num in enumerate(all_number) if num == True])
return Counter(all_number)[True]
时间复杂度 ,空间复杂度 ,以空间换时间。