LeedCode 204. 计数质数
原创
©著作权归作者所有:来自51CTO博客作者tizzi的原创作品,请联系作者获取转载授权,否则将追究法律责任
一、内容
给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。
示例 1:
输入:n = 10
输出:4
解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
示例 2:
输入:n = 0
输出:0
示例 3:
输入:n = 1
输出:0
提示:
0 <= n <= 5 * 106
二、思路
- 埃式筛法:一个数
p
p
p若是一个合数,那么必然可以被
[
2
,
p
−
1
]
[2,p - 1]
[2,p−1]中的某个质数整除,那么我们直接用前面的质数的倍数进行筛除便可以得到所有的质数。n个数中质数的个数大概为
n
/
l
o
g
n
n/logn
n/logn, 而需要枚举的倍数次数为
2
/
n
,
3
/
n
.
.
.
.
.
n
/
n
2/n, 3/n.....n/n
2/n,3/n.....n/n是一个调和级数,当n趋于无穷时可以认为等于
l
o
n
n
lonn
lonn, 因此时间复杂度可以认为为
O
(
n
)
O(n)
O(n),但实际上是
O
(
n
l
o
g
l
o
g
n
)
O(nloglogn)
O(nloglogn)
- 线性筛法: 每个合数只被最小质因子筛一次,因此为
O
(
n
)
O(n)
O(n)。 我们用prime记录所有的质数,然后每次枚举质数来进行筛除,分为两种情况。1.当i % prime[j] != 0时,代表prime[j]不是i的最小质因子,但是是i * prime[j]的最小质因子(因为是从小到大枚举的质数),筛除掉i * prime[j] 2.当i % prime[j] == 0时,prime[j]不仅是i的最小质因子,也是i * prime[j]的最小质因子,因此循环停止。因为后面的质数 * i 都会被最小质因子晒除,不用再重复筛。
三、代码
class Solution {
public:
int countPrimes(int n) {
int ans = 0;
vector<bool> vis(n + 1, true); //判断某个位置是否为质数,true代表是
vis[0] = vis[1] = false;
for (int i = 2; i < n; i++) {
if (vis[i]) {
for (int j = i + i; j <= n; j += i) { //只是用质数来进行筛除
vis[j] = false;
}
}
}
for (int i = 2; i < n; i++)
if (vis[i]) ans++;
return ans;
}
};
class Solution {
public:
int countPrimes(int n) {
int ans = 0;
vector<bool> vis(n + 1, true); //判断某个位置是否为质数,true代表是
vector<int> prime;
for (int i = 2; i < n; i++) {
if (vis[i]) prime.push_back(i); //是质数
for (int j = 0; prime[j] <= n / i; j++) {
vis[i * prime[j]] = false; //利用最小质因子进行筛除
if (i % prime[j] == 0) break; //代表prime[j]是i的最小质因子,那么后面的质数就不用再枚举
}
}
return prime.size();
}
};