求小于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]内 ...
随机推荐
- Spring bean的生命周期详解
bean的生命周期1.实例化bean 即new2.按照spring上下文对实例化的bean进行配置 即填充属性,也就是IOC/DI(控制反转,依赖注入)3.如果这个bean实现了BeanNameAwa ...
- Apache设置二级域名和虚拟主机
apache httpd.conf 最后: ------------------------------NameVirtualHost *:80<VirtualHost *:80> ...
- PHP die与exit的区别
最近听见有人说die和exit区别,bula~bula.决心一探究竟. 翻了翻PHP 5.6的源码(源码的位置为zend目录下zend_language_scanner.l大约是1014~1020行) ...
- 移动端页面点击a标签会有半透明的阴影或红色边框的bug
好久没有更新了,今天来一发 ^_^ 最近在写移动端页面,测试时发现一个a标签的bug:无论是iOS端还是Android端都存在,当点击a标签,会有一个矩形的透明的阴影闪一下(不同的浏览器阴影的颜色还不 ...
- 对于 @Autowired注解和@service注解的理解
@Autowired相当于Spring自动给你进行了new一个对象将这个对象放入你的注解所在类里面. @service 是可以让IOC容器对于你注解的类可以在容器中生成相应的bean实例 便于我们进行 ...
- selenium+chrome抓取淘宝搜索抓娃娃关键页面
最近迷上了抓娃娃,去富国海底世界抓了不少,完全停不下来,还下各种抓娃娃的软件,梦想着有一天买个抓娃娃的机器存家里~.~ 今天顺便抓了下马爸爸家抓娃娃机器的信息,晚辈只是觉得翻得手酸,本来100页的数据 ...
- qt pro 设置编译参数,支持 xp
#兼容 XP VS2015 5.01 版本 win32 { QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS,5.01 QMAKE_LFLAGS_CONSOLE = ...
- 聊聊JavaScript-闭包
今天聊聊闭包,网上五花八门的定义和解释很多很多,是不是搞得你很懵逼:每次看闭包,都不同,本来自己懂,看完别人的之后就开始怀疑自己了.在我看来,闭包简单的说就是函数里面套函数,再往大了说就是我函数外面想 ...
- 【视频教程】一步步将AppBox升级到Pro版
本系列教程分为上中下三部分,通过视频的形式讲解如何将基于FineUI(开源版)的AppBox v6.0一步一步升级FineUIPro(基础版). [视频教程]一步步将AppBox升级到Pro版(上)主 ...
- java读取文件乱码
List<String> lines=new ArrayList<String>(); BufferedReader br = new BufferedReader(new F ...