LeetCode No204. 计数质数(厄拉多塞筛法)

题目描述

在这里插入图片描述

解法1:暴力(超时)

最简单,最容易理解的办法,但是肯定会超时。

class Solution {
    public int countPrimes(int n) {
        int res = 0;
        for (int m = 2; m < n; m++) {
            boolean tag = true;
            for (int i = 2; i <= Math.sqrt(m); i++) {
                if(m % i == 0){
                    tag = false;
                    break;
                }
            }
            if(tag){
                ++res;
            }
        }
        return res;
    }
}

解法2:厄拉多塞筛法

大概的思想如下:
比如10以内的质数有2,3,5,7,由于质数是除了1和自身之外,没有其他因数的数,所以质数是不能被除了1和自身之外的任何数整除的。所以2的倍数(4 6 8 10 …),4的倍数(8,12,16,20,…)一定不是质数。所以就根据这个方法排除就行了。

下面开始演示一遍:

  1. 首先从2开始,由于2是质数,所以2的倍数一定不是质数,给他排除掉
    在这里插入图片描述
    在这里插入图片描述
  2. 遍历到3,由于3是质数,所以3的倍数6 9 12 15…一定不是质数
    在这里插入图片描述
    在这里插入图片描述
  3. 遍历到4时,由于4早已被标记成不是质数,所以跳过
    在这里插入图片描述
  4. 遍历到5时,由于5是质数,所以5的倍数5 10 15 20…一定不是质数
    在这里插入图片描述
    在这里插入图片描述
  5. 按照上面的方法逐一遍历,直到所有数字都被遍历过。
    在这里插入图片描述
    遍历完成后,绿色的是质数,红色的都不是质数。

代码:

class Solution {
    public static boolean[] tag = new boolean[5000010];
    public int countPrimes(int n) {
        int sq = (int) Math.sqrt(n);
        for(int i = 2;i <= sq;++i){
            if(!tag[i]){
                for(int j = i * i;j <= n;j += i){
                    tag[j] = true;
                }
            }
        }
        int res = 0;
        for (int i = 2; i < n; i++) {
            if(!tag[i]){
                ++res;
            }
        }
        return res;
    }
}

问:为什么for循环的起始条件是j = i * i而不是j = i * 2
答:自己画一画就知道了,比如当i遍历到7的时候,应该标记7的倍数(14,21,28,35,42,49,…)为不是素数,如果自己画一画并仔细观察,就会发现14,21,28,35,42早已被标记过了,直接从7的平方49开始标记就可以了。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页