204. 计数质数

Posted by CodingWithAlice on July 6, 2021

204. 计数质数

题目:

统计所有小于非负整数 n 的质数的数量。

解答:

  • 方法一:暴力遍历 - 超时

    时间复杂度:O(n*sqrt(n)),空间复杂度:O(1)

var countPrimes = function (n) {
    let times = 0;
    if (n < 2) {
        return 0
    }
    let isZhi = (x) => {
        // 2 为质数
        if (x === 2) {
            return true;
        }
        // 遍历的最大值 为根号x,算是小小的优化
        for (let i = 2; i <= Math.sqrt(x); i++) {
            if (x % i === 0) {
                return false;
            }
        }
        return true
    }
    for (let i = 2; i < n; i++) {
        if (isZhi(i)) {
            times += 1;
        }
    }
    return times
};
  • 方法二:埃氏筛

image-20210706114101780

时间复杂度:O(nlogn),空间复杂度:O(n)[需要 O(n)的空间记录每个数是否为质数]

  • 主要逻辑:

    从小到大遍历每个数,如果是质数 -> 将该质数的所有倍数都标记为 合数(除了该质数本身)

  • 优化点:

    从质数的 2倍 开始标记是冗余的,应该从 x·x 开始标记,因为 2x、3x…在之前肯定被标记过了

let countPrimes = (n) => {
    if (n < 2) {
        return 0
    }
    let isPrime = new Array(n).fill(1); // 默认所有数为质数
    let res = 0; // 质数数量
    for(let i = 2; i < n; i++) {
        // 如果当前数为质数
        if(isPrime[i]) {
            res += 1;
            //  i * i - 很精髓,因为 i 的那些小于 i 的倍数,如 2i、3i 一定已经被标记过了
            // j += i - 标记小于 n 的,当前质数的所有质数为合数
            for(let j = i * i; j < n; j += i) {
                isPrime[j] = 0;
            }
        }

    }
    return res
}