文章目录
1. 暴力搜索
1.1 思路
根据质数定义,用每一个大于1且小于它本身的整数进行取余运算,如果没有整除情况,则该数为质数。
1.2 复杂度
- 时间复杂度 O(n^2)
- 空间复杂度 O(1)
1.3 代码
class Solution {
public int countPrimes(int n) {
int count = 0;
for (int i = 2; i < n; i++) {
if (isPrime(i)) {
count++;
}
}
return count;
}
private boolean isPrime(int n) {
for (int i = 2; i < n; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
}
2. 暴力搜索优化
2.1 思路
对正整数 n n n,只需用 [ 2 , √ n ] [2, √n] [2,√n] 之间的正整数进行取余运算,如果没有整除情况,则为质数。
2.2 复杂度
- 时间复杂度 O(n^2)
- 空间复杂度 O(1)
2.3 代码
class Solution {
public int countPrimes(int n) {
if (n < 3) {
return 0;
}
int count = 1;
for (int i = 3; i < n; i = i + 2) {
if (isPrime(i)) {
count++;
}
}
return count;
}
private boolean isPrime(int n) {
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
}
3. 厄拉多塞筛选
3.1 思路
对每一个大于1的正整数,如果将它所有的倍数(不包括它本身)排除,那么剩下的必为质数。
3.2 复杂度
- 时间复杂度 O(n)
- 空间复杂度 O(n)
3.3 代码
class Solution {
public int countPrimes(int n) {
int count = 0;
boolean[] flag = new boolean[n];
for (int i = 2; i < n; i++) {
if (!flag[i]) {
count++;
for (int j = i + i; j < n; j += i) {
flag[j] = true;
}
}
}
return count;
}
}
4. 厄拉多塞筛选优化
4.1 思路
使用布尔数组标记是否为质数时,每个数占用四个字节。实际上,完全可以使用一个比特记录逻辑值,即位图法。
4.2 复杂度
- 时间复杂度 O(n)
- 空间复杂度 O(n)
4.3 代码
class Solution {
public int countPrimes(int n) {
int count = 0;
int[] flag = new int[n / 32 + 1];
for (int i = 2; i < n; i++) {
if ((flag[i / 32] & (1 << (i & 31))) == 0) {
count++;
for (int j = i + i; j < n; j += i) {
flag[j / 32] |= 1 << (j & 31);
}
}
}
return count;
}
}