当前位置:网站首页>【基础数学--埃氏筛】204. 计数质数
【基础数学--埃氏筛】204. 计数质数
2022-08-03 03:09:00 【LogosTR_】
题目描述
给定整数 n ,返回所有小于非负整数 n 的质数的数量 。
示例:
输入:n = 10
输出:4
解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
解题思路
概念:
质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
根据概念与题意,自然而然想到从(1, n)的开区间上暴力搜索所有素数(质数)。
判断素数的逻辑从概念上 “除了1和它本身以外不再有其他因数” 上出发,有:
bool isPrime(int x){
if(x < 2) return false;
for(int i = 2; i < x; ++i){
if(x % i == 0) return false;
}
return true;
}
上述判断算法时间复杂度为O(n),嵌入到外层开区间(1, n)的外层循环内,算法整体时间复杂度直接来到O(n^2),当n很大时直接超时。
枚举改良
isPrime()函数中搜索开区间(1, x)中x的因数,假设i是x的因数,那么x / i必定也是x的因数。并且只有当i == sqrt(x)时,有i == x / i,其他情况下,两个因数分布在sqrt(x)左右两侧。
进一步思考,判度素数只需找到一个因数即可返回false,因此我们搜索区间可以缩小到[2, sqrt(x)](查找较小的因数)。整体时间复杂度减小到O(n^1.5)。
bool isPrime(int x){
if(x < 2) return false;
for(int i = 2; i <= sqrt(x); ++i){
if(x % i == 0) return false;
}
return true;
}
埃氏筛
改良后的枚举法时间复杂度还是很大,在C++编译环境下提交依旧会超时,这是因为枚举法终究是忽视区间内数字内在规律的暴力搜索方法。
埃拉托斯特尼筛法,简称埃氏筛或爱氏筛,是一种由希腊数学家埃拉托斯特尼所提出的一种简单检定素数的算法。要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。
仔细分析不难发现这样的规律,假如x是质数,那么x的倍数例如2x、3x、...必为合数 。因此可以这么设计算法,依旧在目标区间(1, n)搜索质数,搜索顺序遵循 由小到大。当搜索到质数时,将其区间内倍数全部标记为合数,由小到大的搜索顺序一定会把下一个质数前的所有合数全部标记。这样就大大减少了判度一个整数是否是质数的次数,进而降低时间复杂度。
其实还是有优化空间的,还是上述假设,x为质数时,2x真的需要我们标记吗?
不用!在搜索到质数2时,上面的2x已经标记过了,搜索到x时再标记2x反而增加了从不必要的操作。
代码实现
改良枚举:
class Solution {
public:
bool isPrime(int x) {
for (int i = 2; i * i <= x; ++i) {
if (x % i == 0) {
return false;
}
}
return true;
}
int countPrimes(int n) {
int ans = 0;
for (int i = 2; i < n; ++i) {
ans += isPrime(i);
}
return ans;
}
};
在n == 5000000时报超出时间限制!
埃氏筛:
class Solution {
public:
int countPrimes(int n) {
int cnt = 0;
vector<int> isPrime(n, 1);
for(int i = 2; i < n; ++i){
if(isPrime[i]){
cnt++;
if((long long) i * i < n){
for(int j = i*i; j < n; j += i){
isPrime[j] = 0;
}
}
}
}
return cnt;
}
};
运行结果:
边栏推荐
- 信号和槽的绑定
- How does Excel compare if two columns of strings are the same?
- ClickHouse - Getting Started
- 【数据分析】基于MATLAB实现SVDD决策边界可视化
- 大佬们,我有点不明白:为什么oracle-cdc的文档写connector可以做到exactly-o
- nVisual信息基础设施可视化管理
- ldap创建公司组织、人员
- sql问题,如何能做到先声明表的名称,例如product202201,表示2022年一月份的货物表,再在声明过的表中查找,下面的代码运行时有错误显示找不到表table_name,请问改如何进行修改
- 我终于逃离了互联网,却陷入了迷茫
- leetcode:172. 阶乘后的零
猜你喜欢

堆的应用:堆排序和TOP-K问题

mysql-installer安装教程(详细图文)

【obs】启动推流失败 : Output.StartStreamFailed 调用流程

Auto.js Pro 编写第一个脚本hello world

Best Practices for Migration from Jincang Database from MySQL to KingbaseES (3. MySQL Database Migration Practice)

Methods annotated with ‘@Async‘ must be overridable

vsftp容器搭建+go开发web用户管理界面(更新于2022.02.23)

IPv4编址;A类、B类、C类、D类、E类IP地址(IP地址;网络地址和主机地址;子网掩码;网关;广播地址;)

Kotlin 乘法、我怎么越乘越小?

如何画一张架构图(内含知识图谱)
随机推荐
22 ES6 knowledge points
Guys, I don't understand a bit: why the documentation of oracle-cdc writes that the connector can be done exactly-o
Incorrect datetime value: '2022-01-01' for function str_to_date
【云原生】灰度发布、蓝绿发布、滚动发布、灰度发布解释
2022-08-01 顾宇佳 学习笔记
Best Practices for Migration from Jincang Database from MySQL to KingbaseES (3. MySQL Database Migration Practice)
什么是数据标注? 数据标注公司主要做什么?
leetcode:172. 阶乘后的零
Get the first/last day of the current week, month, quarter in MySQL
VS中使用BugTrap定位程序崩溃点
ClickHouse - Getting Started
金仓数据库 Pro*C 迁移指南(3. KingbaseES Pr*oc 对 Oracle Pro*c 的兼容)
PSSecurityException
els 计分
sql问题,如何能做到先声明表的名称,例如product202201,表示2022年一月份的货物表,再在声明过的表中查找,下面的代码运行时有错误显示找不到表table_name,请问改如何进行修改
vsftp容器搭建+go开发web用户管理界面(更新于2022.02.23)
Fiddler基本使用
MySQL-Explain详解
uniapp运行到手机,基座提示本应用无法独立运行,需要与hbuilderX 搭配使用
vant-field中colon属性为true报错