题目

给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。

示例 1:

输入:n = 10
输出:4
解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
示例 2:

输入:n = 0
输出:0
示例 3:

输入:n = 1
输出:0

提示:

0 <= n <= 5 * 10^6

思路

埃氏筛,很赞的算法,相比于暴力枚举已经优化了很多。

基本思路是,从204. 计数质数 - 图1开始,对于每个质数,将其的倍数标记为合数。这里有几个细节:

  1. 需要标记的是每个质数的倍数,而不是自然数的倍数,因为合数的倍数一定在之前标记过了。比如204. 计数质数 - 图2的倍数全部标记过后,204. 计数质数 - 图3204. 计数质数 - 图4的倍数就一定标记过了。
  2. 每次只需从自身的平方204. 计数质数 - 图5开始标记,比如对于204. 计数质数 - 图6标记了204. 计数质数 - 图7,到了204. 计数质数 - 图8的时候,204. 计数质数 - 图9就已经标记过了,只需从204. 计数质数 - 图10开始。
  3. 204. 计数质数 - 图11可能溢出,要转为long

代码

  1. class Solution {
  2. public int countPrimes(int n) {
  3. if (n == 0) return 0;
  4. // isComposite[i]表示i是否为合数
  5. boolean[] isComposite = new boolean[n + 1];
  6. int ans = 0;
  7. for (int i = 2; i < n; i++) {
  8. if (!isComposite[i]) {
  9. ans++;
  10. if ((long) i * i >= n) {
  11. continue;
  12. }
  13. for (int j = i * i; j < n; j += i) {
  14. isComposite[j] = true;
  15. }
  16. }
  17. }
  18. return ans;
  19. }
  20. }