求小于n的素数个数
本文是对 LeetCode Count Primes 解法的探讨。
题目:
Count the number of prime numbers less than a non-negative number, n.
尽管题目并没有要我们写一个最优的算法,但是身为一个程序员,优化应该是一种习惯,在编程的过程中,随着思考进行优化。只要求我们满足给定的时间和空间即可。
如果你只能想出一个最简单的方法,难道你会有什么竞争力吗?
穷举
最开始我用的就是这个方法,可以说这是最简单的一种方法了,而且最开始,我就是想的这种方法,说明:我没有对这个问题进行思考,没有去优化它,而作为一个程序员,如何提高效率是拿到一个问题首先要思考的事情。
public int countPrimes(int n) {
int num = 0;
for (int i = 2; i < n; i++) {
boolean flag = true;
for (int j = 2; j < i - 1; j++)
if (i % j == 0) {
flag = false;
break;
}
if (flag) {
num++;
}
}
return num;
}
测试代码:
public static void main(String[] args) {
//获取开始时
long startTime = System.currentTimeMillis();
System.out.println("The num is " + new L_204_Count_Primes().countPrimes(2000000));
long endTime = System.currentTimeMillis();
//获取结束时间
System.out.println("程序运行时间: " + (endTime - startTime) + "ms");
}
时间太长,已经不能计算。
只能是奇数且小于\(\sqrt{n}\)
思考后发现
- 素数一定是奇数
- 若 n=ab 是个合数(其中 a 与 b ≠ 1), 则其中一个约数 a 或 b 必定至大为 \(\sqrt{n}\).
public int countPrimes2(int n) {
int num = 1;
for (int i = 3; i < n; i += 2) {
boolean flag = true;
for (int j = 2; j <= (int) Math.sqrt(i); j++)
if (i % j == 0) {
flag = false;
break;
}
if (flag) {
num++;
}
}
return num;
}
The num is 148933
程序运行时间: 1124ms
试除法:数学知识的运用
查阅 算术基本定理可知:
算术基本定理 :
每个大于1的整数均可写成一个以上的素数之乘积,且除了质约数的排序不同外是唯一的
也就是说我们可以每个数来除以得到的素数,这样可大大减少运行次数。
public int countPrimes3(int n) {
if (n < 3) {
return 0;
}
//0 1 不算做素数,2一定是素数
List<Integer> list = new ArrayList<>();
list.add(2);
boolean flag;
for (int i = 3; i < n; i += 2) {
flag = true;
for (int j = 0; j < list.size() && list.get(j) <= (int) Math.sqrt(n); j++) {
if (i % list.get(j) == 0) {
flag = false;
break;
}
}
if (flag) {
list.add(i);
}
}
return list.size();
}
The num is 148933
程序运行时间: 383ms
筛选法
埃拉托斯特尼筛法,简称埃氏筛,也有人称素数筛。这是一种简单且历史悠久的筛法,用来找出一定范围内所有的素数。
所使用的原理是从2开始,将每个素数的各个倍数,标记成合数。一个素数的各个倍数,是一个差为此素数本身的等差数列。此为这个筛法和试除法不同的关键之处,后者是以素数来测试每个待测数能否被整除。
筛选法的策略是将素数的倍数全部筛掉,剩下的就是素数了,下图很生动的体现了筛选的过程:

筛选的过程是先筛掉非素数,针对本文的题目,每筛掉一个,素数数量-1即可,上面说过素数的一个特点,除了2,其它的素数都是奇数,所以我们只需在奇数范围内筛选就可以了。
public int countPrimes4(int n) {
if (n < 3) {
return 0;
}
//false代表素数,true代表非素数
boolean[] flags = new boolean[n];
//0不是素数
flags[0] = true;
//1不是素数
flags[1] = true;
int num = n - 2;
for (int i = 2; i <= (int) Math.sqrt(n); i++) {
//当i为素数时,i的所有倍数都不是素数
if (!flags[i]) {
for (int j = 2 * i; j < n; j += i) {
if (!flags[j]) {
flags[j] = true;
num--;
}
}
}
}
return num;
}
The num is 148933
程序运行时间: 43ms
全部代码放在:
https://github.com/morethink/algorithm/blob/master/src/algorithm/leetcode/L_204_Count_Primes.java
参考文档:
求小于n的素数个数的更多相关文章
- Educational Codeforces Round 12 F. Four Divisors 求小于x的素数个数(待解决)
F. Four Divisors 题目连接: http://www.codeforces.com/contest/665/problem/F Description If an integer a i ...
- 求小于10000的素数的个数 Exercise06_10
/** * @author 冰樱梦 * 时间:2018年下半年 * 题目:求小于10000的素数的个数 * */ public class Exercise06_10 { public static ...
- 记一次【求n以内的素数个数】的优化记录
最近在leetCode上刷提,还是满锻炼人的,为以后面试打基础吧.不多说下面开始. 问题:求[2,n]之间的素数的个数. 来源:leetCode OJ 提示: Let's start with a i ...
- 【题目】求n以内的素数个数
最近在leetCode上刷提,还是满锻炼人的,为以后面试打基础吧.不多说下面开始. 问题:求[2,n]之间的素数的个数. 来源:leetCode OJ 提示: Let's start with a i ...
- 求1-1e11内的素数个数(HDU 5901 Count primes )
参考链接:https://blog.csdn.net/Dylan_Frank/article/details/54428481 #include <bits/stdc++.h> #defi ...
- LeetCode Count Primes 求素数个数(埃拉托色尼筛选法)
题意:给一个数n,返回小于n的素数个数. 思路:设数字 k =from 2 to sqrt(n),那么对于每个k,从k2开始,在[2,n)范围内只要是k的倍数的都删掉(也就是说[k,k2)是不用理的, ...
- 【NEFU 117 素数个数的位数】(素数定理)
Description 小明是一个聪明的孩子,对数论有着很浓烈的兴趣. 他发现求1到正整数10n 之间有多少个素数是一个很难的问题,该问题的难以决定于n 值的大小. 现在的问题是,告诉你n的值,让你帮 ...
- 求0到n之间素数个数的序列
要求: (1) 找出0-1000之间素数(2) 设f(n)表示0-n之间的素数个数,计算出当n=0,1,2,3,.....,997时f(n)的值,并写入文件 分析: 首先找素数使用一个效率较高的方法- ...
- POJ 3978 Primes(求范围素数个数)
POJ 3978 Primes(求范围素数个数) id=3978">http://poj.org/problem? id=3978 题意: 给你一个区间范围A和B,要你求出[A,B]内 ...
随机推荐
- Maven入门知识介绍
1.1 Maven简介 Apache Maven 是一个软件项目管理工具.基于项目对象模型的概念,Maven可用来管理项目的依赖.编译.文档 等信息. 使用maven管理项目时,项目的依赖的jar包将 ...
- 高仿QQ Xplan的H5页面
概述 这个h5的主要玩法很简单:地球自转的时候会播放背景音乐(比如海浪声),为了找到这个声音是从哪个地球上哪个地方传来的,需要长按下方的按钮,这时地球会自动转动到目标地点,然后镜头拉近,穿过云层,最后 ...
- ansible实践2-拷贝文件或目录
ansible testhost -m copy -a "src=/etc/ansible dest=/tmp/ansibletest owner=root group=root mo ...
- Ajax简单总结
Ajax=异步JS和XML: 主要是局部的数据更新,即不需要刷新整个页面: 首先,需要新建一个XMLHttpRequest对象[这里注意如果是ie7以下的就是创建ActiveXObject]: var ...
- AJAX跨域完全讲解
AJAX跨域完全讲解 今天在慕课网上学习了AJAX跨域完全讲解:https://www.imooc.com/learn/947 我在收集AJAX面试题的时候其实就已经有过AJAX跨域的问题的了,当时候 ...
- DxPackNet 5.视频高质量的压缩和传输
DxPackNet 对视频的压缩和解压也提供了很好的支持,且系统不需要装第三方解码器哦~ 主要用到了 IxVideoEncoder 视频编码器 和 IxVideoDecoder 两个接口 这里只做简 ...
- dubbox系列【四】——使用dubbo-monitor-x监控注册中心
1.下载源码,编译成war包 源码下载地址为:https://git.oschina.net/yjmyzz/dubbo-monitor.git 在pom.xml文件所在目录,直接执行mvn packa ...
- Kotlin——基础的函数/方法详解
对于Kotlin中的函数来说,和JavaScript或者Lua这些语言很像,它有着这些语言的特性.但是也与这些语言就着许多不同之处.或许你更了解Java语言,然而对于Java语言来说,它不是不是闭包这 ...
- 64位Kali无法顺利执行pwn1问题的解决方案
问题描述 环境:VMware Fusion + kali-linux-2018.1-amd64.iso 问题:在Terminal利用./pwn1执行pwn1会出现 bash: ./pwn1:没 ...
- Linux定时及mysql远程
(1)crontab crontab使用方法: (1)使用命令 crontab -e 然后直接编辑定时脚本. 这样执行以后,属于用户自定义的,会被写到 /var/spool/cron 目录下,生成一个 ...