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

🎬 博主名称个人主页

🔥 个人专栏 : 《算法通关》《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;
			} 
	} 

} 

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

相关推荐
你怎么知道我是队长2 小时前
C语言---排序算法5---迭代归并排序法
c语言·算法·排序算法
想进个大厂2 小时前
代码随想录day35 36
算法·leetcode·职场和发展
xqqxqxxq2 小时前
洛谷算法1-2 排序(NOIP经典真题解析)java(持续更新)
java·开发语言·算法
嵌入小生0072 小时前
数据结构 | 常用排序算法大全及二分查找
linux·数据结构·算法·vim·排序算法·嵌入式
近津薪荼2 小时前
优选算法——滑动窗口4(找子串)
c++·学习·算法
2301_822377652 小时前
模板代码异常处理
开发语言·c++·算法
hcnaisd22 小时前
基于C++的游戏引擎开发
开发语言·c++·算法
多恩Stone2 小时前
【3DV 进阶-12】Trellis.2 数据处理脚本细节
人工智能·pytorch·python·算法·3d·aigc
wfeqhfxz25887822 小时前
【目标检测系列】:基于YOLOv10n的MAN卡车超载检测系统·结合FasterCGLU与WFU优化算法_1
算法·yolo·目标检测