算法与数据结构:质数、互质判定和裴蜀定理

文章目录

        • 质数
        • 质数判定
        • 质数筛选
        • 质因数分解
        • 互质判定
        • 裴蜀定理

质数

首先回顾「质数」的定义:若一个正整数无法被除了 1 ​和它自身之外的任何自然数整除,则称该数为质数(或素数),否则称该正整数为合数。

根据上述定义,我们可以得知常见的质数有 2、3、5 等。另外,在整个自然数集合中,质数的分布也比较稀疏,对于一个足够大的整数 N,不超过 N 的质数大约有
N / ln ⁡ ( N ) N/\ln(N) N/ln(N) 个。

质数判定

常见的判定质数的方式是「试除法」,假设自然数 N 不是质数,则一定存在一对数
x, y ,使得下述条件成立:
N = x ⋅ y 1 < x ≤ N ≤ y < N N = x · y \\ 1< x \leq \sqrt N \leq y < N N=xy1<xN y<N

因此我们可以在 [ 2 , N ] [2, \sqrt N] [2,N ] 的范围内枚举 x, 判断 x 是否存在。

如果 x 存在,则 N 为合数;否则 N 为质数。该算法时间复杂度为 O ( N ) O(\sqrt N) O(N )
,具体代码如下所示:

// c语言
bool judgePrime(int n) {for (int i = 2; i * i <= n; i++) {if (n % i == 0) return false;}return true;
}
def judgePrime(n):for i in range(2, int(n**0.5) + 1):if n % i == 0:return Falsereturn True
质数筛选

对于一个正整数 N,一次性求出 1~N 之间所有的质数,即为质数筛选。

显然根据上述「质数判定」的内容,我们可以通过枚举 1~N 的所有数,再依次使用「试除法」来判定其是否为质数,从而完成质数的筛选。但此种方法的时间复杂度过高,为 O ( N N ) O(N\sqrt N) O(NN )

此处将介绍经典的「Eratosthenes 筛法」,也被称为「埃式筛」。该算法基于一个基本判断:任意质数 x 的倍数 ( 2x,3x,… ) 均不是质数。

根据该基本判断,我们得到如下算法过程:

  • 将 2~N中所有数标记为 0
  • 从质数 2 开始从小到大遍历2 ~ N中所有自然数
  • 如果遍历到一个标记为 0 的数 x ,则将其 2~N 中 x 的所有倍数标记为 1

根据上述过程,不难发现如果一个数 x 的标记为 0​,则代表这个数不是 2~(x-1) 中任何数的倍数,即 x 为质数。

接下来我们以 2~10 为例,具体过程如下所示,最终标记为橙色的数为质数:
在这里插入图片描述
Eratosthenes 筛法」的时间复杂度为 O ( N log ⁡ ( log ⁡ ( N ) ) ) O(N\log(\log(N))) O(Nlog(log(N))) ,并不是最快的素数筛法,但在绝大多数的「力扣数学题」中均已够用,且其实现代码较为简单,具体如下所示:

vector<int> primes, vis;
void get_primes(int n) {vis.resize(n + 1, 0);for(int i = 2; i <= n; i++) {if(vis[i] == 0) {primes.push_back(i);for(int j = i; j <= n; j += i) vis[j] = 1;}}
}
# Eratosthenes筛法def get_primes(n):"""获取n以内的所有素数"""if n < 2:return []primes = [True] * (n + 1)primes[0] = primes[1] = Falsefor i in range(2, int(n**0.5) + 1):if primes[i]:for j in range(i * i, n + 1, i):primes[j] = Falsereturn [i for i in range(n + 1) if primes[i]]print(get_primes(100))[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
质因数分解

根据「唯一分解定理」,任何一个大于 1 的正整数都能唯一分解为有限个质数的乘积: N = p 1 c 1 p 2 c 2 … p m c m N = p_1^{c_1}p_2^{c_2}…p_m^{c_m} N=p1c1p2c2pmcm
其中 c i c_i ci 均为正整数,而 p i p_i pi 均为质数,且满足 p 1 < p 2 < … < p m p_1 < p_2 < … < p_m p1<p2<<pm

根据上述定理,我们只需要求出所有的 p i , c i p_i, c_i pi,ci ,即可完成对 N 的质因数分解。
那么如何求取 p i , c i p_i, c_i pi,ci 呢?首先我们考虑如何求 p 1 p_1 p1 c 1 c_1 c1

由于 p 1 < p 2 < … < p m p_1 < p_2 < … < p_m p1<p2<<pm ,且 p 1 p_1 p1 为质数,因此不难发现, p 1 p_1 p1 是 N 所有因子中除 1 以外最小的数。

因此我们可以枚举 2 ~ N 2~\sqrt N 2N 中的所有数 x,如果 N 是 x 的倍数,则 x 为 p 1 p_1 p1。得到 p 1 p_1 p1 后,我们可以令 N 不断除以 p 1 p_1 p1 直至其不再为 p 1 p_1 p1 的倍数,则 c 1 c_1 c1 等于除以 p 1 p_1 p1 的总次数。

得到 p 1 p_1 p1 c 1 c_1 c1 后,N 去除了所有的 p 1 p_1 p1,因此 N 变为 p 2 c 2 … p m c m p_2^{c_2}…p_m^{c_m} p2c2pmcm。又由于 p 1 < p 2 p_1 < p_2 p1<p2 ,因此我们继续枚举 x,如果再次出现 N 是 x 倍数的情况,则 x 为 p 2 p_2 p2

不断使用上述算法,直至循环结束。最后还需判断 N 是否为 1,如果 N 不为 1,则 p m = N , c m = 1 p_m = N, c_m = 1 pm=N,cm=1

该算法的时间复杂度为 O ( l o g ( N ) ) O(log(N)) O(log(N)) ,具体代码如下所示,大家可以配合代码对该算法进行理解:

void divide(int n) {vector<int> p, c;for (int i = 2; i * i <= n; i++) {if (n % i == 0) {p.push_back(i);int num = 0;while(n % i == 0) num++, n /= i;c.push_back(num);}}if (n > 1) {p.push_back(n);c.push_back(1);}
}
# 质因数分解-唯一分解定理def divide(n):"""质因数分解"""i = 2factors = []while i * i <= n:print("i = ", i)print("n = ", n)if n % i:i += 1else:n //= ifactors.append(i)if n > 1:factors.append(n)return factorsprint("质因数分解-唯一分解定理")
print(divide(100))  # [2, 2, 5, 5]
互质判定

首先介绍一下「最大公约数」的概念。如果自然数 c 同时是自然数 a 和 b 的约数,即 a 和 b 同时是 c 的倍数,则 c 为 a 和 b 的公约数。

「最大公约数」就是 a 和 b 的所有公约数中最大的那一个,通常记为 g c d ( a , b ) gcd(a,b) gcd(a,b)

由此我们可以得到「互质」的判定条件,如果自然数 a,b 互质,则 g c d ( a , b ) = 1 gcd(a,b) = 1 gcd(a,b)=1

于是问题变为「如何求 g c d ( a , b ) gcd(a,b) gcd(a,b)?」

此处需要引入「欧几里得算法」,如下所示:
∀ a , b ∈ N , b ≠ 0 , g c d ( a , b ) = g c d ( b , a m o d b ) \forall a,b \in N, b \neq 0, gcd(a,b) = gcd(b, a \quad mod \quad b) a,bN,b=0,gcd(a,b)=gcd(b,amodb)

根据上述算法,可以得到如下代码,其时间复杂度为 O ( l o g ( a , b ) ) O(log(a,b)) O(log(a,b))

int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);
}
裴蜀定理

a , b , x , y , m a, b, x, y, m a,b,x,y,m 是整数,则 a x + b y = m ax+by = m ax+by=m 有解当且仅当 m 是 g c d ( a , b ) gcd(a,b) gcd(a,b) 的倍数。

该定理有一个重要的推论:整数 a,b 互质的充要条件是存在整数 x,y 使 a x + b y = 1 ax+by=1 ax+by=1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/906413.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录算法训练营第60期第四十二天打卡

大家好&#xff0c;今天还是继续我们的动态规划里面的背包问题&#xff0c;前面我们主要接触的是0-1背包和完全背包&#xff0c;其实这两个背包问题主要就是看看每一件物品我们是否有多件&#xff0c;如果每一件物品我们只能取一次的话那这样我们就是0-1背包&#xff0c;如果每…

第41天-Python+Qt四屏播放器开发指南

一、技术选型与工具准备 核心库: Pyqt5:Python标准GUI库,构建用户界面 os / sys:文件系统操作 开发环境: pip install pyqt5 最终效果与运行 import sys from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout # 添加缺失的布局管理器 from PyQt5.QtCore impor…

upload-labs通关笔记-第12关 文件上传之白名单GET法

目录 一、白名单过滤 二、%00截断 1、%00截断原理 2、空字符 3、截断条件 &#xff08;1&#xff09;PHP版本 < 5.3.4 &#xff08;2&#xff09;magic_quotes_gpc配置为Off &#xff08;3&#xff09;代码逻辑存在缺陷 三、源码分析 1、代码审计 &#xff08;1&…

Node.js数据抓取技术实战示例

Node.js常用的库有哪些呢&#xff1f;比如axios或者node-fetch用来发送HTTP请求&#xff0c;cheerio用来解析HTML&#xff0c;如果是动态网页的话可能需要puppeteer这样的无头浏览器。这些工具的组合应该能满足大部分需求。 然后&#xff0c;可能遇到的难点在哪里&#xff1f;…

数据结构(3)线性表-链表-单链表

我们学习过顺序表时&#xff0c;一旦对头部或中间的数据进行处理&#xff0c;由于物理结构的连续性&#xff0c;为了不覆盖&#xff0c;都得移&#xff0c;就导致时间复杂度为O&#xff08;n&#xff09;&#xff0c;还有一个潜在的问题就是扩容&#xff0c;假如我们扩容前是10…

【Unity】DOTween的常用函数解释

DOTween插件常用函数解释 1.DOTween.To&#xff08;通用变化动画&#xff09; 解释&#xff1a;将某一个值在一定的时间内变化到另一个值&#xff08;通用的函数&#xff09;&#xff0c;可用于大部分的动画变化 使用示例&#xff1a; using UnityEngine; using DG.Tweenin…

数据结构测试模拟题(1)

1、约瑟夫问题 #include<bits/stdc.h> using namespace std; const int N25; int e[N],ne[N],head-1,idx1; int n,m; void add_to_head(int x){e[idx]x;ne[idx]head;headidx; } void add(int k,int x){e[idx]x;ne[idx]ne[k];ne[k]idx; } int main(){cin>>n>>…

Helm配置之为特定Deployment配置特定Docker仓库(覆盖全局配置)

文章目录 Helm配置之为特定Deployment配置特定Docker仓库(覆盖全局配置)需求方法1:使用Helm覆盖值方法2: 在Lens中临时修改Deployment配置步骤 1: 创建 Docker Registry Secret步骤 2: 在 Deployment 中引用 Secret参考资料Helm配置之为特定Deployment配置特定Docker仓库(覆…

BERT 作为Transformer的Encoder 为什么采用可学习的位置编码

摘要 BERT 在位置编码上与原始 Transformer 论文中的 sin/cos 公式不同&#xff0c;选择了可学习&#xff08;learned&#xff09;的位置嵌入方案。本文将从 Transformer 原始位置编码选项入手&#xff0c;分析 BERT 选择 learned positional embeddings 的四大核心原因&#x…

【Linux 学习计划】-- gcc、g++、动静态库链接

目录 什么是gcc、g gcc、g 相关操作详解 预处理、编译、汇编、链接来源 动静态链接是什么 结语 什么是gcc、g gcc、g其实就是编译器&#xff0c;是帮助我们从.c或者.cc&#xff0c;.cpp文件编译成可执行程序的 其中&#xff0c;我们如果要编译c语言文件的话&#xff0c;…

前端读取本地项目中 public/a.xlsx 文件中的数据 vue3

前端读取本地项目中 public/a.xlsx 文件中的数据 vue3 项目中需要在 Vue3 项目中读取 public/a.xlsx 文件&#xff0c;可以使用 fetch API 来获取文件内容 一、安装 xlsx 首先&#xff0c;你需要安装 xlsx 库&#xff1a; npm install xlsx二、在需要用的页面里引入xlsx im…

MySQL:to many connections连接数过多

当你遇到 MySQL: Too many connections 错误时&#xff0c;意味着当前连接数已达到 MySQL 配置的最大限制。这通常是由于并发连接过多或连接未正确关闭导致的。 一、查看当前连接数 查看 MySQL 当前允许的最大连接数 SHOW VARIABLES LIKE max_connections;查看当前使用的最大…

2024年热门AI趋势及回顾

人工智能的崛起 2024 年可能会被铭记为人工智能不再是一种技术新奇事物&#xff0c;而是成为现实的一年。微软、Salesforce 和 Intuit 等巨头将人工智能融入主流企业解决方案&#xff1b;从文案写作到数据分析&#xff0c;专门的人工智能应用程序和服务如雨后春笋般涌现&#…

LangFlow技术深度解析:可视化编排LangChain应用的新范式 -(2)流编辑器系统

Flow Editor System | langflow-ai/langflow | DeepWiki 流编辑器系统 相关源文件 流编辑器系统是 Langflow 的核心交互式组件&#xff0c;允许用户直观地创建、编辑和管理 LLM 驱动的应用程序。它提供了一个直观的画布&#xff0c;用户可以在其中添加节点、将其与边缘连接并…

驱动-定时-秒-字符设备

文章目录 目的相关资料参考实验驱动程序-timer_dev.c编译文件-Makefile测试程序-timer.c分析 加载驱动-运行测试程序总结 目的 通过定时器timer_list、字符设备、规避竞争关系-原子操作&#xff0c;综合运用 实现一个程序&#xff0c;加深之前知识的理解。 实现字符设备驱动框…

[Java实战]Spring Boot整合Kafka:高吞吐量消息系统实战(二十七)

[Java实战]Spring Boot整合Kafka&#xff1a;高吞吐量消息系统实战&#xff08;二十七&#xff09; 一、引言 Apache Kafka作为一款高吞吐量、低延迟的分布式消息队列系统&#xff0c;广泛应用于实时数据处理、日志收集和事件驱动架构。结合Spring Boot的自动化配置能力&…

Kotlin Multiplatform--04:经验总结(持续更新)

Kotlin Multiplatform--04&#xff1a;经验总结&#xff08;持续更新&#xff09; 引言 引言 本章用来记载笔者开发过程中的一些经验总结 一、Ktor设置Header 在官方文档中&#xff0c;想要设置Header的示例代码如下&#xff1a; client.get("https://ktor.io&qu…

在 Ubuntu 系统中,将 JAR 包安装为服务

在 Ubuntu 系统中&#xff0c;将 JAR 包安装为服务可以通过 systemd 来实现。以下是详细的操作步骤&#xff1a; 准备工作 确保 JAR 文件路径和 Java 运行时环境已准备好。验证 Java 是否可用&#xff1a; java -version创建 systemd 服务文件 systemd 的服务文件通常位于 …

电商项目-商品微服务-品牌管理微服务开发

一、功能分析 品牌管理微服务包括&#xff1a; &#xff08;1&#xff09;查询全部列表数据 &#xff08;2&#xff09;根据ID查询实体数据 &#xff08;3&#xff09;增加 &#xff08;4&#xff09;修改 &#xff08;5&#xff09;删除 &#xff08;6&#xff09;分页…

Spring Boot开发—— 整合Lucene构建轻量级毫秒级响应的全文检索引擎

文章目录 一、为什么选择 Lucene?轻量级搜索的底层密码二、核心原理:Lucene 的倒排索引2.1 倒排索引:速度之源2.2 段合并优化策略三、Spring Boot集成Lucene实战3.1 依赖配置3.2 实体与索引设计3.3 核心索引服务(含异常处理)3.4 使用示例(测试类)四、高级优化技巧4.1 索…