数学知识:质数相关讲解——质数判定,分解质因数及筛质数

🎬 博主名称个人主页

🔥 个人专栏 : 《算法通关》《Java讲解》

⛺️心简单,世界就简单

序言

今天讲一下质数的内容,下面是目录可以看看
目录

😍质数

😍质数的判定

😁试除法(暴力)

😁优化

😍分解质因数

😁试除法(暴力)

😁优化

😍筛质数

😁思想

😁最朴素算法

😁稍微优化算法---埃氏筛

😁线性筛(欧拉筛)


质数

定义:在大于1的整数中,只含有1和自身这两个约数,就被称为质数

质数的判定

试除法(暴力)

这个是最暴力的写法,时间复杂度是o( n )

cpp 复制代码
bool is_prime(int n){
	if(n < 2) return false;
	for(int i = 2; i < n; i ++){
		if(n % 2 == 0) return false;
	}
	return true; 
} 

优化

如果d | n(| 这个是整除符号,就是如果d能整除n),那么(n/d) | n,比如12,如果2是12的约数,那6也是,3是12的约数,那4也是,所以我们发现他们都是成对存在的。那我们枚举时候,是不是就可以只枚举那一对里较小的一个,也就是d <= n/d,也就是d^2 <= n,也就是d <= sqrt(n),我们就吧时间1优化到了o(sqrt(n)).

我们的写法也很多,比如循环时候写 i <= sqrt(n),这个我们每次循环都要调用,时间比较慢,还有的会写 i * i < n,这个如果我们的 i * i超过了int 范围就会变成负数,我们最终就写i <= n / i,这个就不会超出范围了,

cpp 复制代码
bool is_prime(int n){
	if(n < 2) return false;
	for(int i = 2; i <= n / i; i ++){
		if(n % 2 == 0) return false;
	} 
	return true; 
} 

分解质因数

试除法(暴力)

我们小时候正常写法,可能就是从小到大开始一直枚举所有数

cpp 复制代码
void get_prime(int n){
	for(int i = 2; i <= n; i++){
		if(n % i == 0){
			int s =0 ;
			while(n % i == 0){
				n/=i;
				s ++;
			} 
			printf("%d %d\n", i, s); 
		} 
	} 
} 

优化

我们的循环条件是可以变一下的,我们知道n中最多只包含一个大于sqrt(n)的质因子 ,所以我们枚举时候可以先把小于sqrt(n)的质因子枚举出来,然后最后判断n是不是 > 1,是的话就说明n就是那个大于sqrt(n)的质因子了,这里需要注意的是n是不断在变化的,这里n虽然不断在变化但也不会影响这个算法的正确性,可以拿 n = 34试试

cpp 复制代码
void get_prime(int n){
	for(int i = 2; i <= n / i; i++){
		if(n % i == 0){
			int s =0 ;
			while(n % i == 0){
				n/=i;
				s ++;
			} 
			printf("%d %d\n", i, s); 
		} 
	} 
	if(n > 1) printf("%d %d\n",n , 1);
	puts("");
} 

筛质数

思想

我们基本思想是这样筛的,先写出一串数2 3 4 5 6 7 8 9 10 11 12 ......我们把每个数的倍数都删掉,我们先看2,那我们就把2的倍数都删掉,然后再看3再把3的倍数都删掉........

对于一个P来说,如果他没有被删掉,那就说明从2~P-1里都没有把他删掉,说明P不是2~P-1里任何一个数的倍数,那就说明2~P-1里没有任何一个数是P的约数,那他就是一个质数


最朴素算法

时间复杂度大约是这个o(nlogn),因为计算上稍微繁琐,就不写时间复杂度怎么算的了,可以自己问问ai

cpp 复制代码
void get_prime(int n){
	for(int i = 2; i <= n; i++){
		if(!st[i]){
			primes[cnt ++] = i;
		}
	} 
	for(int j = i + i; j <= n; j += i) st[j] = true; 
} 

稍微优化算法---埃氏筛

我们可以把下面那个循环放入 if 里,我们只需要把质数的倍数给筛掉就行

时间复杂度是o(nloglogn)

cpp 复制代码
void get_prime(int n){
	for(int i = 2; i <= n; i++){
		if(!st[i]){
			primes[cnt ++] = i;
			for(int j = i + i; j <= n; j += i) st[j] = true; 
		}
	} 

} 

线性筛(欧拉筛)

这个基本思路也差不多,就是把每个合数用它的某一个质因子把他筛掉就行

他的思想有两种情况

1, i % primes j == 0. primes j 一定是 i 的最小质因子,primes j 一定是primes j * i 的最小质因子

2,i % primes j != 0. primes j 一定小于 i 的最小质因子,primes j 一定是primes j * i的最小质因子

核心思想:每个合数只被它的最小质因子筛掉一次

stprimes\[ j * i] = true ; 这个就是核心思想

每个合数 x 都可以表示为:

复制代码
x = 最小质因子 × 某个数
在欧拉筛中:primes[j] 是质数i 是当前遍历的数primes[j] × i 就是要标记的合数关键:通过控制 i和 primes[j] 的组合,确保每个合数只被它的最小质因子标记一次

然后为了防止出现重复,如果(i % primesj == 0)我们就break就行

还有就是循环条件

我们要标记的合数是 primes[j] × i,必须满足:primesj × i ≤ n

变形得到 primesj ≤ n / i

cpp 复制代码
const int N = 1e6 +10; 

int primes[N], cnt;
bool st[N]; 

void get_prime(int n){
	for(int i = 2; i <= n; i++){
		if(!st[i]) 	primes[cnt ++] = i;
			for(int j = 0; primes[j] <= n / i; j ++){
				st[primes[j] * i] = true;
				if(i % primes[j] == 0) break;
			} 
	} 

} 

完结下一章讲约数,给个三连吧,谢谢了

相关推荐
Halo_tjn3 分钟前
JDBC 技术的使用
java·算法
Byte不洛5 分钟前
哈希表原理 + 冲突解决 + C++实现
数据结构·c++·算法·哈希算法·散列表
Dillon Dong3 小时前
【风电控制】TI TMS320F28379D 双CPU架构解析与任务分布设计
嵌入式硬件·算法·变流器·风电控制
小羊在睡觉8 小时前
力扣84. 柱状图中最大的矩形
后端·算法·leetcode·golang·go
3DVisionary9 小时前
蓝光三维扫描:医疗制造的精度焦虑怎么解
人工智能·算法·制造·蓝光三维扫描·医疗制造·三维检测·义齿检测
好评笔记9 小时前
机器学习面试八股——常用损失函数
人工智能·深度学习·算法·机器学习·校招
weixin_468466859 小时前
全局与局部注意力机制新手实战指南
人工智能·python·深度学习·算法·自然语言处理·transformer·注意力机制
_日拱一卒9 小时前
LeetCode:994腐烂的橘子
java·数据结构·算法·leetcode·深度优先
珂朵莉MM10 小时前
第七届全球校园人工智能算法精英大赛-算法巅峰赛产业命题赛第3赛季优化题--束搜索
人工智能·算法
Omics Pro10 小时前
首个!外源天然产物综合性代谢图谱
数据库·人工智能·算法·机器学习·r语言