题目描述

统计所有小于非负整数 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 和它本身以外不再有其他因数的自然数。因此对于每个数 x,我们可以从小到大枚举 [2,x-1] 中的每个数 y,判断 y 是否为 x 的因数。但这样判断一个数是否为质数的时间复杂度最差情况下会到 O(n),无法通过所有测试数据。

class Solution {
public:
int countPrimes(int n) {
int cnt=0;
for(int i=2;i<n;i++){
if(isPrime(i)){
cnt++;
}
}
return cnt;
}
bool isPrime(int m){
if(m==0||m==1){
return true;
}
for(int i=2;i<m;i++){
if(m%i==0){
return false;
}
}
return true;
}
};

复杂度分析

时间复杂度:O(n^2)。

空间复杂度:O(1)。

思路二:

考虑到如果 y 是 x的因数,那么 x/y也必然是 x 的因数,因此我们只要校验 y或者x/y即可。而如果我们每次选择校验两者中的较小数,则不难发现较小数一定落在 [2,sqrt(x)]的区间中,因此我们只需要枚举 [2,sqrt(x)]中的所有数即可,这样单次检查的时间复杂度从 O(n) 降低至了 O(sqr(n))

class Solution {
public:
int countPrimes(int n) {
int cnt=0;
for(int i=2;i<n;i++){
if(isPrime(i)){
cnt++;
}
}
return cnt;
}
bool isPrime(int m){
if(m==0||m==1){
return true;
}
for(int i=2;i*i<=m;i++){
if(m%i==0){
return false;
}
}
return true;
}
};

复杂度分析

时间复杂度:O(n*sqrt(n))。单个数检查的时间复杂度为 O(sqrt(n)),一共要检查 O(n) 个数,因此总时间复杂度为 O(n*sqrt(n))

空间复杂度:O(1)。

欢迎关注微信公众号【算法攻城师】

Leetcode No.204 计数质数_i++