思路:
1.逐个遍历:对于x,从2到x逐个相除判断能否整除来判断x是否是质数,O(n2)
2.逐个遍历:对于x,从2到x^1/2逐个相除,优化遍历方法
3.首先考虑到,对于一个数x,他的2x,3x…一定不是质数,那么从小到大遍历的过程中,可以从xx开始到(x+1)x直到n判断数是否是质数(因为当x>2、x>3等时,2x这些数在x==2时就已经判断过了,所以从xx开始判断,将所有不是质数的进行标记,剩下的就是质数)。(如4、9等数在2、3判断时会被标记为不是质数)*
1.题目如下:
给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。
示例 1:
输入:n = 10
输出:4
解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
示例 2:
输入:n = 0
输出:0
示例 3:
输入:n = 1
输出:0
提示:
0 <= n <= 5 * 106
2.代码如下:
class Solution {
public:
//思路一:如果用暴力解锁,时间复杂度会很高 O(n2)
//思路二:优化遍历
/*
主要问题是如何用高效的方法来判断质数
要判断是不是质数,只需要找到它的因子,如果x/y是因数,那么y也是x的因数,我们只需要校验其中的较小值,其中较小的那个因数一定在0-x^1/2范围,所以只需要遍历这个区间的数判断
把遍历判断区间从[0,n]缩小至[0,n^1/2];时间复杂度可以降为O(n*n^1/2),但还是会超时
*/
/*
bool isPrime(int x) {
for (int i = 2; i * i <= x; ++i) {
if (x % i == 0) {
return false;
}
}
return true;
}
int countPrimes(int n) {
int ans = 0;
for (int i = 2; i < n; ++i) {
ans += isPrime(i);
}
return ans;
}
*/
//思路三:埃氏筛
/*
我们在从小到大遍历的时候,对一个质数x,他的2x,3x...一定不是质数;
而且可以从x*x开始来判断,因为当x>2时,对于2x这些在x==2时就已经遍历过了;
每个数便利的时候,记录从x*x到(x+i)*x 到n都不为质数
*/
int countPrimes(int n) {
vector<int> isPrime(n, 1);
int ans = 0;
for (int i = 2; i < n; ++i) {
if (isPrime[i]) {
ans += 1;
if ((long long)i * i < n) {
for (int j = i * i; j < n; j += i) {
isPrime[j] = 0;
}
}
}
}
return ans;
}
};