题:求 0 至 x 的素数的个数。
接触算法之前,我们求素数常常用的是暴力枚举。
但即便是暴力枚举,多琢磨琢磨,我们也能想到优化的思路,如:只需枚举至x的平方根,2的倍数一定不是素数,等等。
暴力枚举是从素数下手的,相对的埃式筛法是从合数下手的。
假设m、n在0-100内,且m*n也在0-100内,那么显然m*n是100以内的一个合数。
/**
* @description: 埃氏筛选
* @param {*} x
* @return {*}
*/
function primeNum (x) {
//创建一个长度为x的空数组。
let arr = Array(x)
//素数计数器。
let count = 0;
for(let i = 2; i < arr.length; i++){
//如果为素数,遍历剔除合数
if(!arr[i]){
count ++
for(let j = i; i * j <= x; j ++){
//将合数标记为true
arr[i * j] = true
}
}
}
//如果return arr 的话会发现其实为101位,因为前面的遍历逻辑是按照自然数来的。
return count;
}
解释下剔除合数的逻辑的几个疑问:
1、为什么从2开始遍历?因为1 * j会把素数也给标记为true。而2*2之前的数(即1、2、3)刚好都为素数。
2、所有合数都能剔除么?假设x为合数,那么存在m*n = x,且 m<x,n<x。而m,n一定比x先遍历。如果m和n中有素数,那么会被我们遍历到;如果m和n都是合数,且m和n中有偶数那么一定会被开始的2遍历到。现在就剩下m和n都为奇数且都为合数的情况。一个数是奇数且为合数,那么相乘等于它的数一定也都是奇数,进而存在更小的值会被先遍历到,直到遇到最小的颗粒度3,5,7,11,17这些不是合数的奇数。