求最大公约数【C/C++】

  大家好啊,欢迎来到本博客( •̀ ω •́ )✧,我将带领大家详细的了解最大公约数的思想与解法。

这只小猫太可爱了,于是我顺手就偷了过来

一、什么是公约数

公约数,也称为公因数,是指两个或多个整数共有的因数。具体来说,如果一个整数能被两个或多个整数整除,那么这个整数就是这些整数的公约数。

例如,考虑整数12和18:

  • 12的因数有 :1, 2, 3, 4, 6, 12

  • 18的因数有:1, 2, 3, 6, 9, 18

12和18的公约数是它们共有的因数,即:1, 2, 3, 6


二、计算最大公约数的方法:

学习数论的一系列算法时,往往直接看算法,是看不懂的。

这里我们先学习数学解法、在给出算法。

1、辗转相除法:(欧几里得算法)
数学:

假设我们有两个正整数 a 和 b,其中 a>b。根据辗转相除法,最大公约数 gcd(a,b) 可以通过以下步骤求得:

  1. 第一步:计算 a mod b,得到余数 r。

  2. 第二步:将 a 替换为 b,将 b 替换为 r。

  3. 第三步:重复上述步骤,直到 b=0 时,此时 a 即为最大公约数。

下方用(18、12)举例。

如图:

代码:
简约背诵版:
#include "iostream"
using namespace std;
// 求公约数
int gcd(int a, int b){
    while(a%b!=0){
        int c = a%b;
        a=b;
        b=c;
    }
    return b;
}

int main(){
    int a,b;
    a = 18;
    b = 12;
    cout<<func(a,b)<<endl;
    return 0;
}
解释版:
// 包含输入输出流头文件,用于使用 cin 和 cout 进行输入输出操作
#include <iostream>

// 使用标准命名空间,这样就可以直接使用标准库中的类和函数,而无需加 std:: 前缀
using namespace std;

/**
 * 函数功能:计算两个整数的最大公约数(Greatest Common Divisor, GCD)
 * 参数:
 *      a: 第一个整数
 *      b: 第二个整数
 * 返回值:
 *      a 和 b 的最大公约数
 * 算法:使用欧几里得算法(辗转相除法)来计算最大公约数
 * 原理:两个整数 a 和 b(a > b)的最大公约数等于 b 和 a % b 的最大公约数
 */
int gcd(int a, int b) {
    // 当 a 除以 b 的余数不为 0 时,继续循环
    while (a % b != 0) {
        // 计算 a 除以 b 的余数,并将其存储在变量 c 中
        int c = a % b;
        // 将 b 的值赋给 a
        a = b;
        // 将余数 c 的值赋给 b
        b = c;
    }
    // 当循环结束时,b 即为 a 和 b 的最大公约数,将其返回
    return b;
}

int main() {
    // 定义两个整型变量 a 和 b,用于存储要计算最大公约数的两个数
    int a, b;
    // 给变量 a 赋值为 18
    a = 18;
    // 给变量 b 赋值为 12
    b = 12;
    // 调用 gcd 函数计算 a 和 b 的最大公约数,并将结果输出到控制台
    cout << gcd(a, b) << endl;
    // 程序正常结束,返回 0 表示成功
    return 0;
}
2、更相减损版(辗转相减法)
数学:

更相减损法是一种古老的算法,用于求两个正整数的最大公约数(GCD)。它最早出现在中国古代数学著作《九章算术》中。以下是更相减损法的数学用法和原理

更相减损法的基本原理是:对于任意两个正整数 a 和 b(假设 a≥b),如果 a 和 b 都是偶数,则可以用 2 约简;如果 a 和 b 不都是偶数,则用较大的数减去较小的数,然后继续对所得的差和较小的数进行同样的操作,直到两个数相等为止。这个相等的数就是它们的最大公约数。

如图:

代码:
简约背诵版: 
#include "iostream"
using namespace std;

int func(int a, int b){
    while(a-b!=0){
        int c = a - b;
        a = b;
        b = c;
    }
    return a;
}

int main(){
    int a,b;
    a = 18;
    b = 12;
    cout<<func(a,b)<<endl;
    return 0;
}
解释版:
// 引入标准输入输出流头文件,该头文件提供了像 cin 和 cout 这样的输入输出功能
// 注意:这里使用双引号包含头文件通常用于自定义头文件,标准库头文件一般用尖括号,应改为 #include <iostream>
#include "iostream"

// 使用标准命名空间 std,这样在后续代码里就可以直接使用标准库中的类和函数,无需添加 std:: 前缀
using namespace std;

/**
 * 函数名: func
 * 功能: 计算两个整数的最大公约数(Greatest Common Divisor, GCD)
 * 参数:
 *      a: 第一个整数
 *      b: 第二个整数
 * 返回值:
 *      a 和 b 的最大公约数
 * 算法: 采用更相减损术来计算最大公约数
 * 原理: 两个正整数 a 和 b(a > b)的最大公约数等于 b 和 a - b 的最大公约数
 */
int func(int a, int b) {
    // 只要 a 与 b 的差值不为 0,就持续循环
    while (a - b != 0) {
        // 计算 a 减去 b 的差值,并将结果存储在临时变量 c 中
        int c = a - b;
        // 把 b 的值赋给 a
        a = b;
        // 把差值 c 的值赋给 b
        b = c;
    }
    // 当 a 与 b 的差值为 0 时,说明此时 a 和 b 相等,这个相等的值就是 a 和 b 的最大公约数,将其返回
    return a;
}

/**
 * 函数名: main
 * 功能: 程序的入口函数,程序从这里开始执行
 * 参数: 无
 * 返回值:
 *      整数 0,表示程序正常结束
 */
int main() {
    // 声明两个整型变量 a 和 b,用于存储要计算最大公约数的两个数
    int a, b;
    // 给变量 a 赋值为 18
    a = 18;
    // 给变量 b 赋值为 12
    b = 12;
    // 调用 func 函数计算 a 和 b 的最大公约数,并将结果输出到标准输出流(通常是控制台)
    // 输出完成后换行
    cout << func(a, b) << endl;
    // 返回 0 表示程序正常结束
    return 0;
}
3、其他方法:

其他方法不像(辗转相除法与更相减损法)那么简便。

所以我在这里,只简单的介绍一下:

1、分解质因数

#include<stdio.h>
void fun(int * arr,int n)
{
	int i = 2, j = 0;
	while (n > 1)
	{
		if (n % i == 0)
		{
			arr[j++] = i;
			n /= i;
		}
		else 
		{
			i++;
		}
	}
}
int gcd(int a,int b) 
{
	//因为要进行找这个数的共有的因数,所以这里用数组来接收
	int arr_a[100] = {0};//放a的所有因数
	int arr_b[100] = {0};//放b的所有因数
	//进行放因数
	fun(arr_a,a);
	fun(arr_b,b);
 
	//找出公共的因数,然后相乘
	int i = 0, j = 0, ret = 1;
	while (arr_a[i] != 0 && arr_b[j] != 0) 
	{
		if (arr_a[i] == arr_b[j]) 
		{
			ret *= arr_a[i];
			i++;
			j++;
		}
		else if (arr_a[i] > arr_b[j])
		{
			j++;
		}
		else
		{
			i++;
		}
	}
	return ret;
}
int main() 
{
	int a = 0;
	int b = 0;
	scanf("%d %d",&a,&b);
	int ret = gcd(a,b);//最大公因数
	printf("%d和%d的最大公因数是:%d",a,b,ret);
	return 0;
}
2、穷举法

法如其名,一个一个的输入测试,最后取出来。

//穷举法
#include<stdio.h>
int main() 
{
	int a = 0;
	int b = 0;
	scanf("%d %d",&a,&b);
	int t = a;
	while (t--)
	{
		if (a % t == 0 && b % t == 0)
			break;
	}
	printf("%d",t);
	return 0;
}
 3、递归法

简单来说,递归法其实就是模拟了辗转相除法。

#include "iostream"
using namespace std;

int gcd(int a, int b){
    if(a%b==0){ // 得到余数
        return b;
    }else{ // 余数为0进入递归
        return gcd(b,a%b); // b放到a的位置,a/b的余数放到b的位置 
    }
}
int main(){
    int a,b;
    a = 18;
    b = 12;
    cout<<gcd(a,b)<<endl;
    return 0;
}

三、练习:

等差数列

题目描述

数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一 部分的数列,只记得其中 NN 个整数。

现在给出这 NN 个整数,小明想知道包含这 NN 个整数的最短的等差数列有几项?

输入描述

输入的第一行包含一个整数 NN。

第二行包含 NN 个整数 A1,A2,⋅⋅⋅,ANA1​,A2​,⋅⋅⋅,AN​。(注意 A1A1​ ∼ ANAN​ 并不一定是按等差数列中的顺序给出)

其中,2≤N≤105,0≤Ai≤1092≤N≤105,0≤Ai​≤109。

输出描述

输出一个整数表示答案。

输入输出样例

示例

输入

5
2 6 4 10 20

输出

10

样例说明: 包含 2、6、4、10、20 的最短的等差数列是 2、4、6、8、10、12、14、16、 18、20

 这道题目说难不难,说简单不简单

1、很多人不会想到用gcd解题,甚至是直接暴力解题,欸!我一会也试试:(vec[n-1]-vec[0])/n,看来是不行的(n不是所有个数)。但是也能用最小差值作为间隔呀,如:d = min(d,gcd(dif[i],dif[i+1])); 这样好像也行,一会试试

2、当然就是这个啦d = min(d,vec[i+1]-vec[i]); 好多人没考虑min,细节容易出错。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 通过递归
int gcd(int a, int b){
    if(a%b==0){
        return b;
    }else{
        return gcd(b,a%b);
    }
}

int main()
{
    int n;
    cin>>n;
    vector<int> vec(n);
    for(int i=0; i<n; ++i){
        cin>>vec[i];
    }
    if(vec.size()==2){ // 特殊情况,只有两个数
        cout<<2<<endl;
        return 0;
    }

    sort(vec.begin(), vec.end());
    vector<int> dif(n-1); // 差集数列

    for(int i=0; i<vec.size()-1; ++i){
        dif[i] = vec[i+1]-vec[i];
    }

    int d = dif[0];
    if(d==0){  // 有没有一种可能,差值为0。
        cout<<n<<endl;
        return 0;
    }
    for(int i=0; i<dif.size()-1; ++i){ // 所有差集的最大公约数
        d = min(d,gcd(dif[i],dif[i+1])); // 为防止结果处,出现更大的差值。
    }

    int num = (vec[vec.size()-1]-vec[0])/d; // d 为0的情况,已经被排除
    if(d==num){
        cout<<vec.size()<<endl;
    }else{
        cout<<num+1<<endl;
    }


    return 0;
}

笔者感悟

学习数论的一系列算法时,往往直接看算法,是看不懂的。

需要先摸清数学思想,胸有成竹之时,写对应算法就更轻松、也记得更牢固。

别人算法理解不透的时候,往往是基础扎的不够牢固。


借鉴博客/视频

1、求最大公约数的几种常见的方法 【详解】


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

conda 配置新环境时package will be install 和 package will be download 的区别

install 和 download 的区别 package will be downloaded下的包&#xff1a;这一类显示的是需要从 conda 仓库或其他指定的源下载的软件包。这些软件包通常是 .tar.bz2、.tar.xz 或 .conda 格式的压缩包。这些包会被下载到本地缓存目录&#xff08;通常是 ~/.conda 或 C:\Users…

【2025小黑课堂】计算机二级WPS精选系列20G内容(可下载:真题+预测卷+软件+选择题)

2025年3月全国计算机等级考试即将于3月29日至31日举行。为了帮助广大考生高效备考&#xff0c;小编特意收集并整理了最新版&#xff08;备考2025年3月&#xff09;的小黑课堂计算机二级WPS 电脑题库软件&#xff0c;助力考生在考试中游刃有余&#xff0c;轻松通关&#xff01; …

C++编写Redis客户端

目录 安装redis-plus-plus库 ​编辑 编译Credis客户端 redis的通用命令使用 get/set exists del keys expire /ttl type string类型核心操作 set和get set带有超时时间 set带有NX string带有XX mset mget getrange和setrange incr和decr list类型核心操作…

①EtherCAT转Modbus485RTU网关多路同步高速采集无需编程串口服务器

EtherCAT转Modbus485RTU网关多路同步高速采集无需编程串口服务器https://item.taobao.com/item.htm?ftt&id798036415719 型号 1路总线EC网关 MS-A2-1011 2路总线EC网关 MS-A2-1021 4路总线EC网关 MS-A2-1041 EtherCAT 串口网关 EtherCAT 转 RS485 技术规格 …

C++ Primer 交换操作

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

TDengine 服务无法启动常见原因

taosd 是 TDengine 的核心服务进程&#xff0c;如果无法启动将导致整个数据库无法使用&#xff0c;了解常导致无法启动的原因&#xff0c;可以帮你快速解决问题。 1. 如何查找日志 无法启动的原因记录在日志中&#xff0c;日志文件默认在 /var/log/taos 的 taosdlog.0 或者 t…

一周学会Flask3 Python Web开发-SQLAlchemy连接Mysql数据库

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili app.py下&#xff0c;我们先配置数据库连接&#xff0c;然后写一个简单sql测试。 连接配置&#xff0c;包括用户名&#xff…

【NLP 32、文本匹配任务 —— 深度学习】

大劫大难以后&#xff0c;人不该失去锐气&#xff0c;不该失去热度&#xff0c;你镇定了却依旧燃烧&#xff0c;你平静了却依旧浩荡&#xff0c;致那个从绝望中走出来的自己&#xff0c;共勉 —— 25.1.31 使用深度学习在文本匹配任务上主要有两种方式&#xff1a;① 表示型 ②…

打造智能聊天体验:前端集成 DeepSeek AI 助你快速上手

DeepSeek AI 聊天助手集成指南 先看完整效果&#xff1a; PixPin_2025-02-19_09-15-59 效果图&#xff1a; 目录 项目概述功能特点环境准备项目结构组件详解 ChatContainerChatInputMessageBubbleTypeWriter 核心代码示例使用指南常见问题 项目概述 基于 Vue 3 TypeScrip…

2008-2024年中国手机基站数据/中国移动通信基站数据

2008-2024年中国手机基站数据/中国移动通信基站数据 1、时间&#xff1a;2008-2024年 2、来源&#xff1a;OpenCelliD 3、指标&#xff1a;网络类型、网络代数、移动国家/地区、移动网络代码、区域代码、小区标识、单元标识、坐标经度、坐标纬度、覆盖范围、测量样本数、坐标…

开源订货系统哪个好 三大订货系统源码推荐

在数字化转型加速的今天&#xff0c;企业对订货系统的需求日益增长。一款优质的订货系统源码不仅能提升供应链效率&#xff0c;还能通过二次开发满足个性化业务需求。这里结合 “标准化、易扩展” 两大核心要求&#xff0c;为您精选三款主流订货系统源码&#xff0c;助您快速搭…

实现插入排序

#include <bits/stdc.h> using namespace std; int a[100005],n; void charu() {for(int i1;i<n;i){int keya[i]; //key表示要排序的数字的数值int ji-1; //j表示前面已排序好的数的个数while(j>0&&key<a[j]){a[j1]a[j]; //把a[j]往后挪j--;}a[j1]…

ROM修改进阶教程------修改安卓机型SELinux宽容的几种方式方法 以及第三方系统中如何关闭SELinux宽容

SELinux是一种强制访问控制安全机制,用于增强Linux系统的安全性。在某些情况下,可能需要对 SELinux 进行宽容设置,以满足特定的应用需求。当SELinux处于宽容模式时,系统允许违反安全策略的行为发生,但不会阻止这些行为,通常会在日志中记录这些违规事件。这与强制模式不同…

MySQL索引数据结构

目录 1 索引常用的数据结构 1.1 二叉树 1.2 平衡二叉树 1.3 红黑树 1.3 Hash表 1.4 B树 1.4 B树 2 MySQL索引的数据结构 2.1 MyISAM存储引擎索引 2.2 InnoDB存储引擎索引 2.2.1 聚集索引 2.2.2 非聚集索引 2.2.3 联合索引数 2.2.4 hash索引 1 索引常用的数据结构 1.1 二叉树 二…

分布式锁—7.Curator的分布式锁一

大纲 1.Curator的可重入锁的源码 2.Curator的非可重入锁的源码 3.Curator的可重入读写锁的源码 4.Curator的MultiLock源码 5.Curator的Semaphore源码 1.Curator的可重入锁的源码 (1)InterProcessMutex获取分布式锁 (2)InterProcessMutex的初始化 (3)InterProcessMutex.…

【高级篇】大疆Pocket 3加ENC编码器实现无线RTMP转HDMI进导播台

【高级篇】大疆Pocket 3加ENC编码器实现无线RTMP转HDMI进导播台 文章目录 准备工作连接设备RTMP概念ENCSHV2推流地址设置大疆Pocket 3直播设置总结 老铁们好&#xff01; 很久没写软文了&#xff0c;今天给大家带了一个干货&#xff0c;如上图&#xff0c;大疆Pocket 3加ENC编…

VS Code连接服务器教程

VS Code是什么 VS Code&#xff08;全称 Visual Studio Code&#xff09;是一款由微软推出的免费、开源、跨平台的代码编辑神器。VS Code 支持 所有主流操作系统&#xff0c;拥有强大的功能和灵活的扩展性。 官网&#xff1a;https://code.visualstudio.com/插件市场&#xff1…

Ubuntu-docker安装mysql

只记录执行步骤。 1 手动下载myql镜像&#xff08;拉去华为云镜像&#xff09; docker pull swr.cn-east-3.myhuaweicloud.com/library/mysql:latest配置并启动mysql 在opt下创建文件夹 命令&#xff1a;cd /opt/ 命令&#xff1a;mkdir mysql_docker 命令&#xff1a;cd m…

【MySQL】事务|概念|如何回滚|基本特性|MySQL事务隔离性具体怎么实现的

目录 1.为啥引入 2.是啥 3.如何回滚&#xff08;日志&#xff09; &#x1f525;4.面试题&#xff1a;谈谈事务的基本特性 &#xff08;1&#xff09;原子性 &#xff08;2&#xff09;一致性&#xff08;收入和支出相匹配&#xff09; &#xff08;3&#xff09;持久性…

C语言中的选择结构:决策的艺术

目录 一、选择结构的概念与意义 二、if语句 1. 基本语法 2. 示例代码 三、if-else语句 1. 基本语法 2. 示例代码 3. 嵌套if-else语句 四、switch语句 1. 基本语法 2. 示例代码 五、选择结构的注意事项 1. 条件表达式的正确性 2. if-else语句的配对问题 3. switch…