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

🎬 博主名称个人主页

🔥 个人专栏 : 《算法通关》《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的最小质因子

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

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

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

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

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

还有就是循环条件

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

变形得到 primes[j] ≤ 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;
			} 
	} 

} 

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

相关推荐
_dindong1 小时前
cf1091div2 C.Grid Covering(数论)
c++·算法
AI成长日志1 小时前
【Agentic RL】1.1 什么是Agentic RL:从传统RL到智能体学习
人工智能·学习·算法
黎阳之光2 小时前
黎阳之光:视频孪生领跑者,铸就中国数字科技全球竞争力
大数据·人工智能·算法·安全·数字孪生
skywalker_112 小时前
力扣hot100-3(最长连续序列),4(移动零)
数据结构·算法·leetcode
6Hzlia2 小时前
【Hot 100 刷题计划】 LeetCode 17. 电话号码的字母组合 | C++ 回溯算法经典模板
c++·算法·leetcode
wfbcg3 小时前
每日算法练习:LeetCode 209. 长度最小的子数组 ✅
算法·leetcode·职场和发展
_日拱一卒3 小时前
LeetCode:除了自身以外数组的乘积
数据结构·算法·leetcode
计算机安禾3 小时前
【数据结构与算法】第36篇:排序大总结:稳定性、时间复杂度与适用场景
c语言·数据结构·c++·算法·链表·线性回归·visual studio
SatVision炼金士3 小时前
合成孔径雷达干涉测量(InSAR)沉降监测算法体系
算法
wuweijianlove3 小时前
算法稳定性与数值误差传播研究的技术2
算法