LeetCode 204:计数质数。暴力解法及优化,筛法解决。

统计所有小于非负整数 n 的质数的数量。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-primes

 

暴力解法:

构建新列表存质数,遍历质数列表,如果n与质数列表的所有数相除余数都不等于0,则为质数,并增加质数列表,否则则不增加。

class Solution:
    def countPrimes(self, n: int) -> int:
        if n <=2:
            return 0
        if n==3:
            return 1
        list_ =[2]
        for item in range(3,n):
            for prime in list_:
                if item % prime ==0:
                    break
            else:
                list_.append(item)
        return len(list_)

 

使用这种解法,力扣运行提示超时,那么该如何优化呢。

当prime>√n 时,则不需要加入质数列表参与除法。举个例子:

如果n为16,√16=4,4以内的质数只有2和3,此时16 能整除2和3,则16不是质数。

如果n为17,√17=4.123,5以内的质数只有2和3,此时17 不能整除2和3,则17是质数。

为什么不用考虑√n以上,参考定理:任何一个合数(非质数),都可以以唯一的形式被写成有限个质数的乘积。

class Solution:
  def countPrimes(self, n: int) -> int:
        if n <=2:
            return 0
        if n==3:
            return 1
        count =1
        list_ =[2]
        for item in range(3,n):
            for prime in list_:
                if item % prime ==0:
                    break
            else:
                count+=1
                if prime < int(n**0.5)+1:
                    list_.append(item)
        return  count

通过优化,已经能跑通用例。

 

 

 

厄拉多塞筛法:

先将 2~n 的各个数放入表中,然后在2的上面画一个圆圈,然后划去2的其他倍数;第一个既未画圈又没有被划去的数是3,将它画圈,再划去3的其他倍数;现在既未画圈又没有被划去的第一个数 是5,将它画圈,并划去5的其他倍数……依次类推,一直到所有小于或等于 n 的各数都画了圈或划去为止。这时,表中画了圈的以及未划去的那些数正好就是小于 n 的素数。

 

class Solution:
    def countPrimes(self, n: int) -> int:
        if n < 3:
            return 0
        list_a = [1] * n
        list_a[0], list_a[1] = 0, 0
        for i in range(2, int(n**0.5)+1):
            if list_a[i] ==1:
                for j in range(i**2,n,i):
                    list_a[j] =0
        return sum(list_a)

 

欧拉筛法:

虽然欧拉筛法是线性的,但是由于厄拉多塞筛法进行了优化,还是比下面的代码稍快一些。

大致思路:

1、生成两个列表,一个用于存质数,一个用于标记是否是质数,先假设全部为质数

2、开始遍历n以内所有正整数i,如果没有被标记为非质数,则将已有的质数列表遍历j与i相乘,得出的数全部标记为合数(分解质因数原理),当i*j的值大于n时,就没有必要继续标记非质数了,因为遍历至n就停止了。

3、如若遍历中遇到数字被标记了非质数则无需在质数列表增加

class Solution:
    def countPrimes(self, n: int) -> int:
        if n < 3:
            return 0
        prime_list = []
        list_ = [1]*n
        for i in range(2, n):
            if list_[i]:
                prime_list.append(i)
            for j in prime_list:
                if j * i >= n:
                    break
                list_[j * i] = 0
                if i % j == 0:
                    break
        return len(prime_list)

 

posted @ 2020-12-03 13:30  韩梅梅op  阅读(188)  评论(0)    收藏  举报