zoukankan      html  css  js  c++  java
  • [LeetCode]Count Primes

     题目:Count Primes

    统计1-n的素数的个数。

    思路1:

    通常的思想就是遍历(0,n)范围内的所有数,对每个数i再遍历(0,sqrt(i)),每个除一遍来判断是否为素数,这样时间复杂度为O(n*sqrt(n))。

    具体实现不在贴代码,过程很简单,两重循环就可以解决。但是效率很差,n较大时甚至会花几分钟才能跑完。

    思路2:

    用埃拉特斯特尼筛法的方法来求素数,时间复杂度可以达到O(nloglogn)。

    首先开一个大小为n的数组prime[],从2开始循环,找到一个质数后开始筛选出所有非素数;

    筛选方法如下:

    1.如果i是素数,则从i*i开始筛选,因为2-i在外循环为2-i的时候已经筛选过了;

    2.筛选掉所有i的倍数的数,即:将prime[k*i] = false;(i < k < n/i)

    思路并不复杂,网上有先将数组分成奇偶再避开偶数,但是这里当外循环开始为2时,内循环从2^2=4开始会把所有的偶数筛掉。

    /**埃氏筛O(nloglogn)**/
    int LeetCode::countPrimes(int n){
        if (n < 1)return 0;
        vector<bool>prime(n + 1,true);
        prime.at(0) = false;
        prime.at(1) = false;
        int count = 0;
        for (size_t i = 2; i < n; i++){
            if (prime.at(i)){
                ++count;
                //从i*i开始筛选,应为2*i、3*i在i为2、3时已经被筛选过;这里是为了筛掉质数i的倍数
                for (size_t j = i*i; j <= n; j += i)prime.at(j) = false;
            }
        }
        return count;
    }

    思路3:

    线性欧拉筛,时间复杂度O(n)。

    上面的筛选法,仔细想想会发现有的合数被重复筛除,例如30,2*15筛了一次,5*6重复筛除,所以也就有了欧拉线性筛法。

    首先,先明确一个条件,任何合数都能表示成一系列素数的积。

    然后利用了每个合数必有一个最小素因子,每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。

    /**线性欧拉筛O(n)**/
    int LeetCode::countPrimes2(int n){
        if (n < 1)return 0;
        vector<bool>flag(n + 1, true);
        vector<int>prime;//保存所有的素数
        flag.at(0) = false;
        flag.at(1) = false;
        int count = 0;
        for (size_t i = 2; i < n; i++){
            if (flag.at(i)){//记录素数的个数
                ++count;
                prime.push_back(i);
            }
            //任何合数都能表示成一系列素数的积,然后利用了每个合数必有一个最小素因子,每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。
            for (size_t j = 0; j < count && i*prime.at(j) < n; j++){
                flag.at(i*prime.at(j)) = false;//素数的倍数
                if (!(i % prime.at(j)))break;//保证每个数只被最小素数筛选一次
            }
        }
        return count;
    }

    if (!(i % prime.at(j)))break;//保证每个数只被最小素数筛选一次

    prime数组中的素数是递增的,当 i 能整除 prime[j],那么 i*prime[j+1] 这个合数肯定被 prime[j] 乘以某个数筛掉。

    因为i中含有prime[j], prime[j] 比 prime[j+1] 小。接下去的素数同理。所以不用筛下去了。

    在满足i%prme[j]==0这个条件之前以及第一次满足改条件时,prime[j]必定是prime[j]*i的最小因子。

    还不清楚的可以参考一下这篇博客:http://blog.csdn.net/nk_test/article/details/46242401

  • 相关阅读:
    SugarCRM 主表自定义字段日期型
    算法导论46 VLSI芯片测试
    算法导论14.18
    算法导论13.24
    poj1980 Unit Fraction Partition **
    算法导论5.12
    算法导论76 对区间的模糊排序
    红黑树(redblack tree)算法,附AVL树的比较
    poj1856 Sea Battle *
    算法导论42 找出所缺的整数
  • 原文地址:https://www.cnblogs.com/yeqluofwupheng/p/6783563.html
Copyright © 2011-2022 走看看