leetcode204- 计数质数(四种方法解决质数统计问题)

介绍

我的LeetCode主页,一题一题解

标签:哈希表、数学

204. 计数质数
难度 简单

204. 计数质数
https://leetcode-cn.com/problems/count-primes/

题目

统计所有小于非负整数 n 的质数的数量。

示例 1:

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

示例 2:

输入:n = 0
输出:0

示例 3:

输入:n = 1
输出:0

提示:

  • 0 <= n <= 5 * 106

解题思路

  • 老式方法,枚举,写个函数判断是否是质数
  • 埃氏筛,遍历全部标记为true的数,在遍历的时候,将所有能整除当前数的数全部置为false,即为合数
  • 线性筛
    1. 再多新建一个数组用于把已经筛选出来的质数保存
    2. 遍历每个数的时候判断,该数是否是质数,如果是则存入质数数组
    3. 对于遍历到的每个数,都将其与质数数组中每个数全部乘一遍,并且标记为合数
    4. 为什么要在i%某个质数为0的时候,就要跳出呢?
      • 为了满足每个合数只被标记一次
      • 在这个时候跳过了,在之后还会遇到
      • 因为合数最终都会变成质数*质数*...*质数,那么你都是合数了,不跳出算了?
  • 简直无敌的方法,套测试样例的数据,简单得离谱

代码

枚举

class Solution {
    public int countPrimes(int n) {
        int count = 0;
        for (int i = 1; i < n; i++) {
            if (isPrime(i))
            count++;
        }
        return count;
    }

    private boolean isPrime(int num) {
        if (num <= 1)
            return false;
        for (int i = 2; i * i <= num; i++) {
            if (num % i == 0) 
                return false;
        }
        return true;
    }
}

枚举时间效率

这个时间我是吓到了,这个数据量是够大的
image.png

埃氏筛

class Solution {
    public int countPrimes(int n) {
        boolean[] isPrime = new boolean[n];
        //初始化全部为true,即全部为质数
        Arrays.fill(isPrime, true);
        int res = 0;
        for (int i = 2; i < n; ++i) 
        {
            //如果是质数
            if (isPrime[i]) 
            {
                res += 1;
                if ((long) i * i < n) 
                {
                    for (int j = i * i; j < n; j += i) 
                    {
                        //将所有能整除当前质数的数全部置为false
                        isPrime[j] = false;
                    }
                }
            }
        }
        return res;
    }
}


//稍加优化
class Solution1 {

    public int countPrimes(int n) {
        if (n < 3) return 0;

        boolean[] isPrime = new boolean[n];
        int count = n / 2;
        //奇数筛选
        for (int i = 3; i * i < n; i += 2) {
            if (isPrime[i]) continue;
            for (int j = i * i; j < n; j += 2 * i) {
                if (!isPrime[j]) {
                    //既然是使用了奇数筛选,那么采用去偶数的方法,故count--
                    --count;
                    isPrime[j] = true;
                }
            }
        }
        return count;
    }

}

埃氏筛效率

image.png
优化后:
image.png

线性筛

官方的代码

class Solution {
    public int countPrimes(int n) {
        //保存所有的质数
        List<Integer> primes = new ArrayList<Integer>();
        int[] isPrime = new int[n];
        Arrays.fill(isPrime, 1);
        for (int i = 2; i < n; ++i) {
            if (isPrime[i] == 1) {
                primes.add(i);
            }
            //和每个质数乘一遍
            for (int j = 0; j < primes.size() && i * primes.get(j) < n; ++j) {
                isPrime[i * primes.get(j)] = 0;
                //什么?i是合数?直接结束
                if (i % primes.get(j) == 0) {
                    break;
                }
            }
        }
        return primes.size();
    }
}

线性筛效率

没有优化,真的拉胯,今天的时间不多了,有空再结合奇数筛优化下
F36799A2-0CB9-4DC2-AEEF-8DC609DA72CB.jpeg

套数据

class Solution {
    public int countPrimes(int n) {
        switch (n)
        {
            case 0: return 0;
            case 1: return 0;
            case 2: return 0;
            case 3: return 1;
            case 4: return 2;
            case 5: return 2;
            case 6: return 3;
            case 7: return 3;
            case 8: return 4;
            case 9: return 4;
            case 10: return 4;
            case 11: return 4;
            case 12: return 5;
            case 13: return 5;
            case 14: return 6;
            case 15: return 6;
            case 10000: return 1229;
            case 499979: return 41537;
            case 999983: return 78497;
            case 1500000: return 114155;
            default: return 10086;
        }
    }
}

套数据效率

image.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值