204. Count Primes

这里写图片描述
题目大意:
给一个非负整数n,求小于n的素数的个数

思路:
第一反应是采用素数的定义来做。

(1)如果采用素数的定义,即不能被1和它本身整除,需要从2计算到它减一,举个栗子,如果要验证17是素数,则需要计算17 / 2,17 / 3,17 / 4 … 17 / 16,O(n)级别的复杂度。伪代码如下:

for(int i = 2; i < n; i++) {
    // 此处是判断n是否可以被i整除的代码
}

(2)当然,可以对其优化,我们知道,一个数不能被大于它1/2的数整除,(17的1/2是8.5) 17不能被9、10、11… 16 整除,因此可以减小循环的范围。伪代码如下:

for(int i = 2; i < n / 2 + 1; i++) {
    // 此处是判断n是否可以被i整除的代码
}

(3)继续优化。如果p、q的乘积为n,即p * q = n,令p为p、q中较小的那个即:p <= q,则可以推出 p <= sqrt(n),可以继续减小循环的范围。伪代码如下:

for(int i = 2; i < sqrt(n) + 1; i++) {
    // 此处是判断n是否可以被i整除的代码
}

(4)当然,我也没有这么傻,如果数据量大,使用上述的方法一定会超时,所以我打了个表。首先初始化一个数组arr,里面存布尔型变量,初始化时均未True,如果arr[i] = True,表示 i 是素数,False表示 i 不是素数。这里的思路是,首先假设所有数都是素数,然后把不是素数的逐个剔除,最后剩下的都是素数。很der的思路。对于一个i,它的倍数一定不是素数,根据这个原理写了一个从2到n的循环:


for(int i = 2; i < n; i++) {
    for (int j = 2; i * j < n; j++) {
        // i * j 一定不是素数
        arr[i*j] = False;
    }
}

然后就这么交了,,一共20个用例,在第18个用例时,即当n = 999983,超时!
(5)其实仔细分析一下也可以看出问题,打表打得不对,有重复判断的现象,比如15这个数,在3上判断了一次,是3的5倍。在5上又判断了一次,是5的3倍,这样就重复判断了。对于5而言,不必再计算5 * 3了,直接从5 * 5开始计算就可以了。

简单的讲:

因为2是素数、所以 22、23、24都不是素数
因为3是素数、所以3
3、34、35都不是素数
因为5是素数、所以55、56、5*7都不是素数

Python代码:

import math

class Solution(object):
    
    def countPrimes(self, n):
        """
        :type n: int
        :rtype: int
        """
        # 打表
        arr = [True for i in range(n)]
        m = int(math.sqrt(n)) + 1
        for i in range(2, m):
            if arr[i]:
               for j in range(i*i, n, i):
                   arr[j] = False 

        count = 0
        for i in range(2, len(arr)):
            if arr[i]:
                count += 1
                print(i)

        return count

附java代码

class Solution {
    public int countPrimes(int n) {
        boolean[] isPrime = new boolean[n];
        int m = (int)Math.sqrt(n) + 1;
        for(int i = 2; i < m; i++) {
            if(!isPrime[i]) {
                for(int j = i * i; j < n; j+=i) {
                    isPrime[j] = true;
                }    
            }
        }
        
        int count = 0;
        for(int i = 2; i < n; i++) {
            if(!isPrime[i]) {
                count++;
            }
        }
        return count;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值