给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。
示例 1:
输入:n = 10
输出:4
解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
示例 2:
输入:n = 0
输出:0
示例 3:
输入:n = 1
输出:0
提示:
- 0 <= n <= 5 * 106
解法一:枚举求解
考虑质数的定义:在大于 1 的自然数中,除了 1 和它本身以外不再有其他因数的自然数。因此对于任何整数n,我们都能从小到大枚举[2,n-1]中的 x,判断 x 是否能被 n 整除,如果能,则n是质数。这里的时间复杂度为O(n)。继续考虑,如果 x 能被 n 整除,那么 n/x 也能被 n 整除,因此只需要校验 x 或者 n/x 就能判断 n 是不是质数。Math.min(n/x,x)一定落在[2,Math.sqrt(x)] 的区间中,因此对于整数 n,只需要判断[2,Math.sqrt(x)]是否有因子即可。这样单次检测的事件复杂度从O(n)减低到O(Math.sqrt(n))。
返回所有小于非负整数 n 的质数的数量,只需要判断从 2 到 n-1 的数是否是质数。
typescript
function isPrime(n:number) {
for(let i = 2; i * i <= n; i++) {
if(n%i===0) {
return false
}
}
return true
}
function countPrimes(n: number): number {
let count = 0
for(let i = 2; i < n; i++) {
if(isPrime(i)){
count++
}
}
return count
}
解法二:埃氏筛
如果 x 是质数,那么 x 的 j 倍,例如 2x,3x... 一定不是质数,利用可以从这里入手优化时间复杂度。
ini
function countPrimes(n: number): number {
const isPrimeArr = new Array(n).fill(1)
let count = 0
for(let i = 2; i < n; i++) {
if(isPrimeArr[i]) {
count++
for(let j = 2;i * j < n;j++) {
isPrimeArr[i * j] = 0
}
}
}
return count
}
时间复杂度:O(nloglogn),空间复杂度:O(n)。