LeetCode | 204. Count Primes 数论 素数筛选,厄拉多塞筛法

Count the number of prime numbers less than a non-negativenumber, n.

Example:

Input: 10

Output: 4

Explanation: There are 4 prime numbers less than10, they are 2, 3, 5, 7.


这一题给你一个n,让你统计小于N的所有的素数的个数。

假如按照传统的方法去做,即遍历每一个小于n的数i,然后遍历所有小于i的数j,然后判断i  % j == 0 是否成立,以此来判断i是否是素数,那么时间复杂度为O(n^ 2),绝对会超时。

这里可以使用一个经典的素数筛选算法,能够很快的得到小于n的所有素数,这个方法的全称为厄拉多塞筛法,今天才知道这个算法的名字。。。

西元前250年,希腊数学家厄拉多塞(Eeatosthese)想到了一个非常美妙的质数筛法,减少了逐一检查每个数的的步骤,可以比较简单的从一大堆数字之中,筛选出质数来,这方法被称作厄拉多塞筛法(Sieve of Eeatosthese)。

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

操作起来大概是这样,首先从2开始遍历,一直遍历到n,当数组中某个值为true的时候,说明这个数i是素数,把数组中所有的小于n的i的倍数都置为false,因为这些数为合数,

遍历完2 ~ √ n + 1之后,数组中所有值为true的数就是小于n的所有的素数

证明起来也很简答,首先2肯定是素数,其标记为true,然后把2的所有倍数设置为false,在之后的遍历过程中,假如某个数a是素数,那么a不是任何一个数的倍数,也就是说a不可能被设置为false,一定是true,假如某个数是合数,那么这个数一定存在一个最小的素数因子,当遍历到这个素数因子的时候,这个数一定会被设置为false

总而言之,数组中所有的素数最后都为true,所有的合数最后都为false

这里还需要注意一定,假如要使用For进行遍历的话,使用xrange而不是range,range会生成一个序列而不是迭代器,会消耗更多的时候,

然后当创建一个有多个重复内容的数组的时候,尽量使用 AA = [A] * n的形式,创建,这里需要注意的是,当A是变量的时候,AA是一个有n个变量A的数组,当A是对象的时候,包括数组对象,AA是一个有n个对象A拷贝的数组,所以当A是对象的时候,要这样创建 AA = [ A for I in range(n)],这样才能创建n个独立的A对象,这在创建二维数组的时候要特别注意

class Solution(object):
    def countPrimes(self, n):
        """
        :type n: int
        :rtype: int
        """
        theCheck = [True] * (n + 1)
        theCount = 0
        for i in xrange(2, n):
            if theCheck[i]:
                theCount += 1
                for j in xrange(i, n):
                    if j * i > n: break
                    else:
                        theCheck[i * j] = False
        return theCount

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值