Java程序员如何使用代码来计算最大公约数和最小公倍数?

news2025/1/20 15:52:06

沉淀、分享、成长,让自己和他人都能有所收获!😄

一、前言

嘿,怎么突然讲到最大公约数了?

因为RSA算法,对于与欧拉结果计算的互为质数的公钥e,其实就需要使用到辗转相除法来计算出最大公约数。

放心,你所有写的代码,都是对数学逻辑的具体实现,无非是难易不同罢了。所以如果你真的想学好编程思维而不只是CRUD,那就要把数据结构、算法逻辑等根基打牢。

二、短除法

既然都说到这了,那你还记得怎么计算最大公约数吗,死鬼?

以上这种方式就是我们在上学阶段学习的,这种计算方式叫做短除法。

短除法:是算术中除法的算法,将除法转换成一连串的运算。短除法是由长除法简化而来,当中会用到心算,因此除数较小的除法比较适用短除法。对大部分的人而言,若除以12或12以下的数,可以用记忆中乘法表的内容,用心算来进行短除法。也有些人可以处理除数更大的短除法。—— 来自维基百科

三、欧几里德算法

短除法能解决计算最大公约数的问题,但放到程序编写中总是很别扭,总不能一个个数字去试算,这就显得很闹挺。其实除了短除法还有一种是计算公约数的办法,叫做欧几里德算法。

欧几里德算法:是计算两个整数(数字)的最大公约数【GCD(Greatest Common Divisor)】的有效方法,即能将它们整除而无余数的最大数。它以古希腊数学家 欧几里得的名字命名,欧几里德在他的几何原本(约公元前 300 年)中首次描述了它。它是算法的示例,是根据明确定义的规则执行计算的分步过程,并且是常用的最古老的算法之一。它可以用来减少分数到他们的最简单的形式,并且是许多其他数论和密码计算的一部分。—— 来自维基百科

GCD,代表了两个数字的最大公约数,GCD(X,Y) = Z,那么就表示 X 和 Y 的最大公约数是 Z。由欧几里德算法给出 GCD(X,Y) = GCD(Y,XmodY) —— mod 表示求模计算余数。

其实简单来说就是,X和Y的公约数是Z,那么Y和Z的公约数也是Z。24和18的最大公约数是6,那么18和6的公约数也是6。嘿,就这么一个事。但就因为有了这一样一条推论,让编程代码变得优雅舒服,只需要不断地将X、Y两数作差,就能计算最大公约数。

😂 这让小编想起,多年前上学时候,我也给出过一条推论;”任意一组所能构成等差数列的三个数字,所能组合出来的一个三位数,都能被3整除。“ 例如:等差数列 163146 组合成三位数 463116 或者 461631 都能被3整除。

四、辗转相除法代码实现

欧几里德算法 = 辗转相除法法:en.wikipedia.org/wiki/Euclid…

在辗转相除法的实现中,计算最大公约数的方式,就是使用一个数字减去另外一个数字,直到两个数字相同或者有其中一个数字为0,那么最后不为零的那个数字就是两数的最大公约数。

在这里提供了2种计算方式,一种是循环另外一种是递归。—— 方便很多看不懂递归的小伙伴可以用另外的方式学习。

1. 循环实现

public long gcd01(long m, long n) {
    m = Math.abs(m);
    n = Math.abs(n);
    
    while (m != 0 && n != 0 && m != n) {
        if (m > n) {
            m = m - n;
        } else {
            n = n - m;
        }
    }
    return m == 0 ? n : m;
}
复制代码
  • 两数循环处理中,条件为 m != 0 && n != 0 && m != n 直至循环结束。

2. 递归实现

public long gcd02(long m, long n) {
    if (m < n) {
        long k = m;
        m = n;
        n = k;
    }
    if (m % n != 0) {
        long temp = m % n;
        return gcd02(n, temp);
    } else {
        return n;
    }
}
复制代码
  • 计算方式逻辑和条件是一样的,只不过这个是使用了递归调用的方式进行处理。

3. 测试验证

@Test
public void test_euclidean() {
    Euclidean euclidean = new Euclidean();
    System.out.println(euclidean.gcd01(124, 20));
    System.out.println(euclidean.gcd02(124, 20));
}
复制代码

测试结果

4
4


Process finished with exit code 0
复制代码
  • 计算 124 和 20 的最大公约数,两个计算方式结果都是 4 。好的,到这测试通过。
  • 这并不是一个很难的知识点,但当你做一些技术分享、答辩述职等时候,能这样用技术语言而不是大白话的讲述出来后,其实高度就有了。兄弟!👬🏻

在 stackoverflow.com 看到一道问题:计算两个整数的最小公倍数的最有效方法是什么?

乍一看,🤨 这能有啥。不就是计算下最小公倍数吗?但一想我脑袋中计算最小公倍数的方法;一种是在本子上通过短除法计算,另外一种是基于计算出的最大公约数,再使用公式:lcm(a, b) = |a * b| / gcd(a, b) 求得最小公倍数。—— 计算最大公约数是基于欧几里德算法(辗转相除法)

那么这样的计算方法是不是最有效的方法,另外如果是同时计算多个整数的最小公倍数,要怎么处理?

其实编程的学习往往就是这样,留心处处都是学问,你总是需要从各种细小的点中,积累自己的技术思维广度和纵向探索深度。好啦,接下来就给大家介绍几种用于计算最小公倍数的算法。

五、用公约数实现

公式:lcm(a, b) = |a * b| / gcd(a, b)

public long lcm01(long m, long n) {
    return ((m == 0) || (n == 0)) ? 0 : Math.abs(m * n) / gcd(m, n);
}

private long gcd(long m, long n) {
    m = Math.abs(m);
    n = Math.abs(n);
    // 从一个数字中减去另一个数字,直到两个数字变得相同。
    // 这将是 GCD。如果其中一个数字为零,也退出循环。
    // https://en.wikipedia.org/wiki/Euclidean_algorithm
    while (m != 0 && n != 0 && m != n) {
        if (m > n) {
            m = m - n;
        } else {
            n = n - m;
        }
    }
    return m == 0 ? n : m;
}
复制代码
  • 首先这里是一个比较简单的方式,基于两数乘积除以最大公约数,得到的结果就是最小公倍数。

六、简单累加计算

此计算方式为,在一组正整数数列中,通过找到最小的数字进行自身累加循环,直至所有数字相同时,则这个数字为最小公倍数。—— 你能代码实现一下吗?

public long lcm02(long... n) {
    long[] cache = n.clone();
    // 以所有数字都相等作为条件
    while (!isEquals(n)) {
        System.out.println(JSON.toJSONString(n));
        long min = n[0];
        int idx = 0;
        for (int i = 0; i < n.length; i++) {
            if (min > n[i]) {
                min = n[i];
                idx = i;
            }
        }
        n[idx] = cache[idx] + min;
    }
    return n[0];
}
复制代码
  • 在代码实现中,首先要把n个整数数列进行克隆保存。因为每次相加的都是最初的这个数列里的数字值。接下来就是以所有数字都相等作为条件循环判断,不断地的累加最小的数值即可。最终返回的就是最小公倍数。

七、表格推演计算

表格计算方式为将一组数字以最小的质数2开始整除,直到不能被2整除后,用下一个质数3继续整除(剩余的数字中比大的最小的质数)直至所有数字都为1的时候结束。最终所有有效的质数乘积就是最小公倍数。—— 想想如果这让你用代码实现,你能肝出来吗?

public long lcm03(long... n) {
    Map<Long, List<Long>> keys = new HashMap<>();
    for (long key : n) {
        keys.put(key, new ArrayList<Long>() {{
            add(key);
        }});
    }
    System.out.print("执行表格计算:\r\nx ");
    long primality = 2, cachePrimality = primality, filterCount = 0, lcm = 1;
    // 以所有元素最后一位为1作为条件
    while (filterCount != keys.size()) {
        int refresh = 0;
        filterCount = 0;
        for (Map.Entry<Long, List<Long>> entry : keys.entrySet()) {
            long value = entry.getValue().get(entry.getValue().size() - 1);
            if (value == 1) {
                filterCount++;
            }
            // 整除处理
            if (value % primality == 0) {
                entry.getValue().add(value / primality);
                refresh++;
            } else {
                entry.getValue().add(value);
            }
        }
        // 刷新除数
        if (refresh == 0) {
            for (Map.Entry<Long, List<Long>> entry : keys.entrySet()) {
                long value = entry.getValue().get(entry.getValue().size() - 1);
                // 找到下一个符合的素数
                if (value > primality || (value < cachePrimality && value > primality)) {
                    cachePrimality = value;
                }
                entry.getValue().remove(entry.getValue().size() - 1);
            }
            primality = cachePrimality;
        } else {
            // 累计乘积
            lcm *= cachePrimality;
            System.out.print(cachePrimality + " ");
        }
    }
    keys.forEach((key, values) -> {
        System.out.println();
        for (long v : values) {
            System.out.print(v + " ");
        }
    });
    System.out.println("\r\n");
    return lcm;
}
复制代码
  • 在代码实现中我们通过 Map 作为表的key,Map 中的 List 作为表每一行数据。通过这样一个结构构建出一张表。
  • 接下来以所有元素最后一位为1作为条件循环处理数据,用最开始的2作为素数整除列表中的数据,并保存到下一组数列中。当2不能整除时,则刷新素数,选取另外一个列表中最小的素数作为除数继续。
  • 这个过程中会累计有效素数的乘积,这个乘积的最终结果就是最小公倍数。

八、测试验证

单元测试

@Test
public void test_euclidean() {
    LastCommonMultiple lastCommonMultiple = new LastCommonMultiple();
    // System.out.println("最小公倍数:" + lastCommonMultiple.lcm01(2, 7));
    System.out.println("最小公倍数:" + lastCommonMultiple.lcm02(3, 4, 6));
    // System.out.println("最小公倍数:" + lastCommonMultiple.lcm03(3, 4, 6));
     System.out.println("最小公倍数:" + lastCommonMultiple.lcm03(3, 4, 6, 8));
   //System.out.println("最小公倍数:" + lastCommonMultiple.lcm03(4, 7, 12, 21, 42));
}
复制代码

测试结果

执行累加计算:
[3,4,6]
[6,4,6]
[6,8,6]
[9,8,6]
[9,8,12]
[9,12,12]
最小公倍数:12

执行表格计算:
x 2 2 2 3 
3 3 3 3 1 
4 2 1 1 1 
6 3 3 3 1 
8 4 2 1 1 

最小公倍数:24
复制代码
  • 到这里测试就结束了,本章一共介绍了三种计算最小公倍数的方法。那如果只让你看到逻辑,你能写出最终的代码吗?

九、常见面试

  • 最大公约数的使用用途?
  • 如何使用代码实现最大公约数计算?
  • 你是否了解欧几里德算法?
  • 关于数论你还记得多少?
  • RSA 加密算法为什么需要用到公约数计算?
  • 如何计算两数的最小公倍数?
  • 如果计算多个整数的最小公倍数?
  • 你能说一下具体如何实现这种X的计算流程吗?
  • 你知道最小公倍数计算的用途吗?

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

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

相关文章

Java文件IO操作

目录 一、了解什么是文件 狭义的文件&#xff1a; 广义的文件&#xff1a; 二、文件的路径 ①文件的绝对路径 ②文件的相对路径 三、Java对于文件的操作 File类的构造方法 File类的普通方法 四、对于文件的内容操作 ①FileInputStream&#xff08;文件输入流&#xf…

ES索引备份还原

ES索引备份还原一、规划二、备份方案一&#xff1a;备份到集群共享目录方案二&#xff1a;备份到HDFSES还原一、规划 es数据出于线上数据安全考虑&#xff0c;对于es已有的索引数据可以进行安全备份&#xff0c;通常可以将es备份到共享文件目录或者一些其它的数据存储的文件系…

Splashtop Personal 安装教程

splashtop Personal 安装教程1. Splashtop Personal 概述2. splashtop Personal 安装步骤2.1 主控端&#xff08;Splashtop Business app&#xff09;2.2 被控端&#xff08;Splashtop Streamer&#xff09;2.3 打开主控端结束语1. Splashtop Personal 概述 Splashtop Persona…

java跳出循环的几种方式

在java中可以使用break、continue、return语句跳出for循环。break用于完全结束一个循环&#xff0c;跳出循环体&#xff1b;continue只是中止本次循环&#xff0c;接着开始下一次循环&#xff1b;return的功能是结束一个方法。 break语句 break用于完全结束一个循环&#xff0…

4.5 集成运放的种类及选择

一、集成运放的发展概述 集成运放自 20 世纪 60 年代问世以来&#xff0c;飞速发展&#xff0c;目前已经历了四代产品。 第一代产品基本沿用了分立元件放大电路的设计思想&#xff0c;采用了集成数字电路的制造工艺&#xff0c;利用了少量横向 PNP 管&#xff0c;构成以电流源…

Axure 原型设计的三步进阶法

平时跟很多同学朋友的交流过程中&#xff0c;对于axure的需要做到怎样&#xff0c;众说纷纭。总结了一下大家的意见&#xff0c;分别有以下几种&#xff1a; 1、掌握基本的搭建方法即可&#xff0c;不需要做交互&#xff1b; 2、既然做就要做到尽善尽美&#xff0c;页面和交互…

【Python百日进阶-数据分析】Day221 - plotly使用日期类型轴的时间序列 2

文章目录九、具有自定义日期范围的时间序列图9.1 使用plotly.express9.2 使用graph_objects9.3 手动设置日期范围十、带范围滑块的时间序列十一、带范围选择器按钮的时间序列十二、按缩放级别自定义刻度标签格式十三、隐藏周末和假期13.1 隐藏正常周末13.2 隐藏周末和指定日期1…

Windows 11关闭系统更新的方法有哪些?

之前问的最多的就是Win10关闭更新的方法&#xff0c;现在轮到了Windows11&#xff0c;下面我们就具体来看看如何关闭Windows11的系统更新。方案一&#xff1a;使用注册表编辑器关闭Win11更新Windows注册表实质上是一个庞大的数据库&#xff0c;存储着各种各样的计算机数据与配置…

Windows系统下Python安装教程

Python安装环境为Windows10系统&#xff08;64&#xff09; 1.Python下载 选择Python官网进行下载&#xff08;Welcome to Python.org&#xff09;&#xff0c;进入网站&#xff0c;点击Downloads&#xff0c;进入下载模块&#xff0c;鼠标指针放到Download&#xff0c;选择Wi…

聚焦行业,2022巨杉客户案例及产品荣获多项殊荣

2022年&#xff0c;巨杉客户实践案例及产品 广受肯定&#xff0c;荣获多项殊荣 荣誉不仅属于巨杉 它源自于每一位客户的信任和支持 感谢每一位客户对巨杉产品的选择和认可 客户创新实践案例 巨杉联合江阴农商行获评爱分析银行数字化创新实践案例 9月&#xff0c;在“2022…

InstallShield 制作INF驱动安装程序

题外话&#xff1a; 使用INF文件制作经过签名的CAT文件可以参考如下博文&#xff1a; https://blog.csdn.net/qq_29729577/article/details/113537243 回归正题&#xff1a; 本例使用InstallShield 2020版本 驱动文件准备 将INF、CAT、SYS等驱动相关文件放至同一目录下&…

【动态内存管理】C语言

前言&#xff1a; 为什么会存在动态内存分配 我们以前学过的开辟空间的方式有两个特点&#xff1a; 1 空间开辟大小是固定的&#xff1b; 2.数组在申明的时候&#xff0c;必须指定数组的长度&#xff0c;它所需要的内存在编译时分配&#xff1b; 但是对于空间的需求&#xff0c…

Qt基于CTK Plugin Framework搭建插件框架--插件通信【注册接口调用】

文章目录一、前言二、插件完善2.1、添加接口文件2.2、添加接口实现类2.3、服务注册&#xff08;Activator注册服务&#xff09;三、接口调用四、接口 - 插件 - 服务的关系4.1、1对14.2、多对14.3、1对多一、前言 通过Qt基于CTK Plugin Framework搭建插件框架–创建插件一文&am…

解决方案|Keithley吉时利源表测试软件的典型应用及案例介绍

数字源表又称源测量单元(SMU)&#xff0c;是数字万用表(DMM)、电压源、实际电流源、电子负载和脉冲发生器的有用功能集成在仪器中&#xff0c;相当于电压源、电流源、电压表、电流表和电阻表的综合体可以作为四象限电压源或电流源提供精确的电压或电流&#xff0c;同时测量电流…

聚类模型(K-means聚类,系统聚类,DBSCAN算法)

所谓的聚类&#xff0c;就是将样本划分为由类似的对象组成的多个类的过程。聚类后&#xff0c;我们可以更加准确的在每个类中单独使用统计模型进行估计、分析或预测&#xff1b;也可以探究不同类之间的相关性和主要差异。聚类和分类的区别&#xff1a;分类是已知类别的&#xf…

Kafka 生产者

Kafka 生产者 生产者就是负责向 Kafka 发送消息的。 生产者业务逻辑 &#xff08;生产者业务逻辑流程&#xff09; 生产者开发示例 一个正常的生产逻辑流程如下&#xff1a; 配置生产者客户端参数及创建相应的生产者实例 构建待发送的消息 发送消息 关闭生产者实例 生…

CSS权威指南(八)基本元素框

文章目录1.基本元素框2.内边距3.边框4.轮廓5.外边距1.基本元素框 文档中每个元素都会生成一个矩形框&#xff0c;我们称之为元素框。这个框体描述元素在文档布局中所占的空间。因此&#xff0c;元素框之间是有影响的&#xff0c;涉及位置和尺寸。 &#xff08;1&#xff09;宽…

如何在 Excel VBA 中插入行

在本文中,我将解释如何使用VBA(Visual Basic for Applications)在Excel中插入行。VBA 是一种编程语言,适用于在Excel和其他Office程序中工作的人员,因此可以通过编写所谓的宏来自动化Excel中的任务。使用VBA编码,我们可以执行Excel中执行的所有大多数任务,就像复制、粘贴…

【手写 Vue2.x 源码】第十六篇 - 生成 render 函数 - 代码拼接

一&#xff0c;前言 上篇&#xff0c;生成 ast 语法树 - 构造树形结构部分 基于 html 特点&#xff0c;使用栈型数据结构记录父子关系开始标签&#xff0c;结束标签及文本的处理方式代码重构及ast 语法树构建过程分析 本篇&#xff0c;使用 ast 语法树生成 render 函数 - 代…

双软认证-深圳市

双软认证是软件企业的认证和软件产品的登记&#xff0c;企业申请双软认证除了获得软件企业和软件产品的认证资质&#xff0c;同时也是对企业知识产权的一种保护方式&#xff0c;更可以让企业享受国家提供给软件行业的税收优惠政策。 想要在这个残酷的市场中生存下去的话&#x…