LintCode 1324: Count Primes

  1. Count Primes

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

Example
Example 1:

Input: n = 2
Output: 0
Example 2:

Input: n = 4
Output: 2
Explanation:2, 3 are prime number

解法1:普通筛法。
记得i循环到sqrt(n)就可以了。不知道有没有更好的办法。
空间复杂度O(n),时间复杂度O(nloglogn)。这里O(nloglogn)接近O(n),因为loglogn接近于常数。

class Solution {
public:
    /**
     * @param n: a integer
     * @return: return a integer
     */
    int countPrimes(int n) {
        if (n == 1) return 0;
        int sqrtn = sqrt(n);
        vector<int> filter(n, 1);
        
        for (int i = 2; i <= sqrtn; ++i) {
            int j = i << 1;
            while (j < n) {
                filter[j] = 0;
                j += i;
            }
        }
        int count = 0;
        for (int i = 1; i <= n; ++i) {
            if (filter[i] == 1) {
                count++;
            }
        }
        
        return count - 1;   //1 is not prime
    }
};

解法2:也是普通筛法。
下面的解法也可以。但当n>=46350后会出错,因为n*n>MAX_INT

class Solution {
public:
    /**
     * @param n: a integer
     * @return: return a integer
     */

    int countPrimes(int n) {
        vector<int> flags(n + 1, 0);
        for (int i = 2; i <= n; ++i) {
            if (flags[i]) continue;
            //fails after i >=46350 as i*i exceeds MAX_INT
            for (int j = i * i; j <= n; j += i) {
                flags[j] = 1;
            }
        }
        int count = 0;

        
        for (int i = 2; i < n; ++i) {
            if (!flags[i]) count++;
        }
        return count;   //1 is not prime
    }
};

解法3:线性筛法。时间复杂度O(n)。很不错!
关于线性筛法的介绍见
https://zhuanlan.zhihu.com/p/42609585

class Solution {
public:
    /**
     * @param n: a integer
     * @return: return a integer
     */

    int countPrimes(int n) {
        vector<int> primes(n + 1, 0); //primes[i]: 0 => unprocessed, -1 => non-prime, >0 => a prime-number
        int count = 0;
        for (int i = 2; i < n; ++i) {
            if (!primes[i]) {
                primes[count++] = i;
            }
            for (int j = 0; j < count; ++j) {
                int product = primes[j] * i;
                if (product > n) break;
                primes[product] = -1; //just show it is not prime-number. It can be any number except 0.
                if (i % primes[j] == 0) break;
            }
        }
        return count;
    }
};

解释如下:
参考https://zhuanlan.zhihu.com/p/42609585
(3).对于一个数k,总是进行从nprime[0]~nprimej,直到if(n%prime[j]==0)成立时break掉

这是这个算法的精髓所在,所以弄清楚原因是十分必要的!!!

对于一个数c=ab(b为c的最小质因数),当通过该算法的循环循环至cb时,易得此时c%b==0,如果此时继续循环至b后面的一个素数d,则有:cd=abd=(ad)b,因为d>b,所以ad>c。当循环从c继续查找到ad时我们发现当ad再次与素数b想乘时,就又对c*d进行了一次操作,出现了冗余,所以在if(n%prime[j]==0)成立时要将该层循环break掉;

举个例子,对于一个数9,92=18将18标记为合数,循环继续;93=27将27标记为合数,此时发现9%3=0,循环退出。如果将循环继续下去会出现筛除95=45的情况,而45=153,在15时会被在筛去一次,故不可行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值