求小于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]内 ...
随机推荐
- Azure Automation (5) 调整Azure SQL Database DTU
<Windows Azure Platform 系列文章目录> 之前有客户提了需求,在9点以后,把Azure SQL Database DTU提高 在凌晨,把Azure SQL Datab ...
- Java实现单链表的快速排序和归并排序
本文描述了LeetCode 148题 sort-list 的解法. 题目描述如下: Sort a linked list in O(n log n) time using constant space ...
- ASP.NET Core 发布 centos7 配置守护进程
ASP.NET Core应用程序发布linux在shell中运行是正常的.可一但shell关闭网站也就关闭了,所以要配置守护进程, 用的是Supervisor,本文主要记录配置的过程和过程遇到的问题 ...
- Oracle,Sql,procedure 感觉自己写的很棒的一个存储过程
感觉自己写的很棒的一个Oracle存储过程,(其实想说很叼^,^). 集成了一堆操作数据的功能(至少几十), 包括存储过程执行异常信息输出帮助诊断. 亮点很多, 比如`over(partition b ...
- [bzoj3998][TJOI2015]弦论-后缀自动机
Brief Description 给定一个字符串, 您需要求出他的严格k小子串或非严格k小子串. Algorithm Design 考察使用后缀自动机. 首先原串建SAM, 然后如果考察每个状态代表 ...
- 通过读取配置文件,启动mongodb
在实际的项目中,经常利用mongodb数据库做缓存,mongodb的并发性比较高,所以对于快速存储.读取信息有很多优点.在项目中对于第一次的数据请求会直接访问数据库,而对于获得的信息通常都会在此时刻存 ...
- 分享:Python中的位运算符
按位运算符是把数字看作二进制来进行计算的.用的不太多,简单了解. 下表中变量 a 为 60,b 为 13二进制格式如下: a = 0011 1100 b = 0000 1101 a&b = 0 ...
- 【Unity3D技术文档翻译】第1.2篇 为打包 AssetBundles 准备资产
本章原文所在章节:[Unity Manual]→[Working in Unity]→[Advanced Development]→[AssetBundles]→[Preparing Assets f ...
- Mysql(一):初识数据库
一 数据库管理软件的由来 基于我们之前所学,数据要想永久保存,都是保存于文件中,毫无疑问,一个文件仅仅只能存在于某一台机器上. 如果我们暂且忽略直接基于文件来存取数据的效率问题,并且假设程序所有的组件 ...
- bzoj 2217 [Poi2011]Lollipop 乱搞 贪心
2217: [Poi2011]Lollipop Time Limit: 15 Sec Memory Limit: 64 MBSec Special JudgeSubmit: 383 Solved ...