题目描述:
统计所有小于非负整数 n 的质数的数量。
示例:
输入: 10
输出: 4
解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
解法1:
厄拉多塞筛法:
先将2-N的各数放入表中,然后在2的上面画一个圆圈,然后划去2的其他倍数;第一个既未画圈又没有被划去的数是3,将它画圈,再划去3的其他倍数;现在既未画圈又没有被划去的第一个数 是5,将它画圈,并划去5的其他倍数……依次类推,一直到所有小于或等于N的各数都画了圈或划去为止。这时,表中画了圈的以及未划去的那些数正好就是小于 N的素数。
在实现过程中,可以设置一个长度为n的数组,将所有值设为1.
然后从索引为2的数开始遍历数组,2是第一个质数,count加1,将所有索引2的倍数处的数置为0.直到2的倍数大于n为止
继续遍历数组,找到下一个不为0的数,count加1,将索引为该数字的倍数处的数字置为0,直到倍数大于n为止
class Solution(object):
def countPrimes(self, n):
"""
:type n: int
:rtype: int
"""
a=[1]*n
count=0
for i in range(2,n):
if a[i]==1:
count+=1
j=1
while i*j<n:
a[i*j]=0
j+=1
return count
评论区用时少的写法:
arr=[1]*n
arr[0],arr[1]=0,0
for i in range(2,int(n**0.5)+1):
if arr[i]:
arr[i*i:n:i]=[0]*((n-1)//i-i+1)
return sum(arr)
解法2:
直观写法,质数是只能被1和其本身整除:
这种做法本题超时
num=0
for i in range(2,n):
flag=1
for j in range(2,i):
if i%j==0:
flag=0
break
if flag==1:
num+=1
return num
解法3:
质数还有一个特点,就是它总是等于 6x-1 或者 6x+1,其中 x 是大于等于1的自然数。
首先 6x 肯定不是质数,因为它能被 6 整除;其次 6x+2 肯定也不是质数,因为它还能被2整除;依次类推,6x+3 肯定能被 3 整除;6x+4 肯定能被 2 整除。那么,就只有 6x+1 和 6x+5 (即等同于6x-1) 可能是质数了。所以循环的步长可以设为 6,然后每次只判断 6 两侧的数即可。
这种方法本题也超时
count=0
for num in range(n):
if num==1:
continue
if num == 2 or num == 3: # 两个较小的数进行处理
count+=1
continue
if num % 6 != 1 and num % 6 != 5: # 不在6的倍数的两侧的一定不是质数
continue
tmp = int(math.sqrt(num))
flag=1
for i in range(5, tmp+1): # 在6的倍数两侧的也可能不是质数
if num % i == 0:
flag=0
if flag==1:count+=1
return count