Leetcode 204 - Count Primes(素数筛法)

23 篇文章 0 订阅

题意

计算小于n的整数中素数的个数。

思路

算法1

埃氏筛(Eratosthenes),时间复杂度 O(nloglogn)

从2开始,每个素数的整数倍都是合数。

优化:若i是素数,从 ii 开始筛除合数而不是 i2

wiki: https://zh.wikipedia.org/wiki/%E5%9F%83%E6%8B%89%E6%89%98%E6%96%AF%E7%89%B9%E5%B0%BC%E7%AD%9B%E6%B3%95

代码:

class Solution {
public:
    int countPrimes(int n) {
        vector<int> notPrime(n, 0);
        for (int i = 2; i < n; i++) {
            if (!notPrime[i]) {
                for (long long j = (long long) i * i; j < (long long) n; j += i) {
                    notPrime[j] = 1;
                }    
            }
        }
        //1 is not prime
        int cnt = 0;
        for (int i = 2; i < n; i++) {
            if (!notPrime[i]) cnt++;
        }
        return cnt;
    }
};
算法2

快速线性筛法,时间复杂度 O(n)

确保:

  1. 每个合数都会被筛除掉。
  2. 每个合数只会被筛除一遍。

优于埃氏筛的思想:12可以由6 * 2筛除掉,也可以由3 * 4筛除掉,会重复筛选,因为我们需要一定的措施来确保每个合数只会被筛除一遍。

结合代码分析:

class Solution {
public:
    int countPrimes(int n) {
        vector<int> prime(n, 0);
        vector<int> notPrime(n, 0);
        int tot = 0;
        for (int i = 2; i < n; i++) {
#1          if (!notPrime[i]) prime[tot++] = i;
#2           for (int j = 0; j < tot, (long long) prime[j] * i < (long long) n; j++) {
                 notPrime[i * prime[j]] = 1;
#3               if (i % prime[j] == 0) break;
            }
        }
        return tot;
    }
};

#1 若i没有被筛除,那么我们将i添加到素数表内。

#2 通过 iprime[j] 来筛除合数:
1. 当 i 是素数的时候,有iprime[j],我们用 p1 表示 i p2表示 j ,那么我们筛除出来的数p=p1p2(p1>p2)。我们需要证明 p 在之前没有被筛除过:假设p之前被筛除过,那么 p=q1q2...qn (且 qi 为素数),即有 p1p2=q1q2...q2 ,因为都为素数,即 p1,p2,q1,q2...,qn 之间无公约数。所以不会相等。
2. 当 i 是合数的时候,从1我们我们知道i=p1p2...pnp1>p2...>pn。那么,我们新筛选出来的素数 p=iq ,且一定有 qpn (通过#3来保证这个条件)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值