如何判断一个区间内的质数数量?

问题

质数是指在大于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

时间复杂度 O ( n 2 ) O(n^{2}) ,空间复杂度 O ( 1 ) O(1)

方法二,枚举+数学优化

注意到,因数都是成对出现的,比如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	

时间复杂度 O ( n 1.5 ) O(n^{1.5}) ,空间复杂度 O ( 1 ) O(1)

方法三,枚举+数学优化+剪枝

注意到任何大于等于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

时间复杂度 O ( n 1.5 ) O(n^{1.5}) ,空间复杂度 O ( 1 ) O(1) ,但是相比于方法二省去了很多不必要的判断,总体上优于方法二。

方法四,埃拉托斯特尼筛法

给出要筛数值的范围n,找出 n {\displaystyle {\sqrt {n}}} 以内的素数 p 1 , p 2 , , p k {\displaystyle p_{1},p_{2},\dots ,p_{k}} 。先用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]

时间复杂度 O ( n ) O(n) ,空间复杂度 O ( n ) O(n) ,以空间换时间。

发布了11 篇原创文章 · 获赞 17 · 访问量 3112

猜你喜欢

转载自blog.csdn.net/weixin_43208423/article/details/105407789
今日推荐