面试中算法(最大公约数)

高效求出两个整数的最大公约数,要尽量优化算法的性能。

def getDiv(a,b):
    ma=max(a,b)
    mi=min(a,b)
    #判断能被整除
    if ma%mi==0:
        return mi
    #递归
    return getDiv(ma%mi,mi)

if __name__ == '__main__':
    # print(getDiv(10, 25))
    print(getDiv(1000, 50))

没错,这确实是辗转相除法的思路。不过有一个问题,当两个整数较大时,做 a%b取模运算的性能会比较差。

更相减损术,出自中国古代的《九章算术》,也是一种求最大公约数的算法。
它的原理更加简单:两个正整数a和b (a>b),它们的最大公约数等于a-b的差值c和较小数b的最大公约数。例如,10和25,25减10的差是15,那么10和25的最大公约数,等同于10和15的最大公约数。

def getDiv(a,b):
    #如果相等,就是最大公约数
    if a==b:
        return a
    #求出最大值,最小值
    ma=max(a,b)
    mi=min(a,b)
    #递归调用
    return getDiv(ma-mi,mi)


if __name__ == '__main__':
    print(getDiv(100, 75))

更相减损术依靠两数求差的方式来递归,运算次数肯定远大于辗转相除法取模方式。如计算10000和1的最大公约数,就要递归9999次! 

有什么办法可以既避免大整数取模,又能尽可能地减少运算次数呢?

最优方法:把辗转相除法和更相减损术的优势结合起来,在更相减损术的基础上使用移位运算。

当a和b均为偶数时,gcd (a,b) =2xgcd (a/2,b/2)=2xgcd (a>>1,b>>1)。

当a为偶数,b为奇数时,gcd (a,b) = gcd (a/2,b) = gcd (a>>1,b)。

当a为奇数,b为偶数时,gcd (a,b) = ged (a,b/2) = ged (a,b>>1)。

当a和b均为奇数时,先利用更相减损术运算一次,gcd (a,b) = gcd (b,a-b),此时a-b必然是偶数,然后又可以继续进行移位运算。 

其中:gcd是求最大公约数的方法,a是第一个数,b是第二个数。

def getDiv3(a,b):
    #如果相等,就是最大公约数
    if a==b:
        return a
    #a,b都为偶数,,则a,b都右移1位,再乘以2
    if(a&1)==0 and (b&1)==0:
        return getDiv3(a>>1,b>>1) <<1
    # a为偶数,b为奇数,则a右移1位
    elif (a&1)==0 and (b&1)!=0:
        return getDiv3(a>>1,b)
    # a为奇数,b为偶数,则b右移1位
    elif (a&1)!=0 and (b&1)==0:
        return getDiv3(a,b>>1)
    else:
        #求出最大值,最小值
        ma=max(a,b)
        mi=min(a,b)
        #递归调用
        return getDiv3(ma-mi,mi)


if __name__ == '__main__':
    print(getDiv3(10, 25))
    print(getDiv3(10000, 55))

总之:

1.辗转相除法:时间复杂度不太好计算,可以近似为O(log (max (a,b)) ),但是取模运算性能较差。

2.更相减损术:避免了取模运算,但是算法性能不稳定,最坏时间复杂度为O (max (a,b) ) 。

3.更相减损术与移位相结合:不但避免了取模运算,而且算法性能稳定,时间复杂度为O(log (max (a,b) ) ) 。

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

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

相关文章

C++笔试强训day14

目录 1.乒乓球框 2.组队竞赛 3.删除相邻数字的最⼤分数 1.乒乓球框 链接 哈希表直接秒了&#xff1a; #include <iostream> #include <string> using namespace std; int main() {string s1, s2;while (cin >> s1 >> s2) { // 未知组数的输⼊int h…

新芯计划(1)时钟资源——MMCM与PLL

系列文章目录 1、同步设计——亚稳态 文章目录 系列文章目录前言一、时钟管理资源二、MMCM与PLLMMCM内部结构&#xff1a;PLL内部结构:区别 前言 本节围绕时钟资源展开&#xff0c;主要描述和比较MMCM和PLL&#xff0c;若内容有误&#xff0c;欢迎和感谢各位指正 参考视频&am…

IoTDB 入门教程 基础篇③——基于Linux系统快速安装启动和上手

文章目录 一、前文二、下载三、解压四、上传五、启动六、执行七、停止八、参考 一、前文 IoTDB入门教程——导读 二、下载 下载二进制可运行程序&#xff1a;https://dlcdn.apache.org/iotdb/1.3.1/apache-iotdb-1.3.1-all-bin.zip 历史版本下载&#xff1a;https://archive.…

Mysql中索引的概念

索引相关概念 基础概念&#xff1a; 在MySQL中&#xff0c;索引是一种数据结构&#xff0c;用于加快数据库查询的速度和性能。索引可以帮助MySQL快速定位和访问表中的特定数据&#xff0c;就像书籍的索引一样&#xff0c;通过存储指向数据行的指针&#xff0c;可以快速…

《老相册》读后感

外面在下着瓢泼大雨&#xff0c;豆粒大的雨点打在窗户上&#xff0c;发出啪啪的巨响。这样的雨天&#xff0c;是不适宜外出的&#xff0c;最惬意的方式就是一个人待在宿舍里&#xff0c;打开一本书&#xff0c;慢慢地看&#xff0c;静静地想&#xff0c;让所有的烦恼融化在这雨…

二叉树的迭代遍历 | LeetCode 144. 二叉树的前序遍历、LeetCode 94. 二叉树的中序遍历、LeetCode 145. 二叉树的后序遍历

二叉树的前序遍历&#xff08;迭代法&#xff09; 1、题目 题目链接&#xff1a;144. 二叉树的前序遍历 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3]示例 2&#x…

Docker Compose 部署若依前后端分离版

准备一台服务器 本次使用虚拟机&#xff0c;虚拟机系统 Ubuntu20.04&#xff0c;内存 4G&#xff0c;4核。 确保虚拟机能连接互联网。 Ubuntu20.04 安装 Docker 添加 Docker 的官方 GPG key&#xff1a; sudo apt-get update sudo apt-get install ca-certificates curl su…

1850H-The Third Letter

题目链接&#xff1a;The Third Letter 本道题目就是带权并查集的模板题&#xff0c;但又好久没学忘了&#xff0c;再复习一遍。。。 路径压缩函数模板&#xff1a; int root(int x){if(pre[x]!x){int troot(pre[x]);d[x]d[pre[x]];pre[x]t;}return pre[x]; } 之后就模拟一…

eNSP-浮动静态路由配置

ip route-static 192.168.1.0 24 192.168.3.2 preference 60 #设置路由 目标网络地址 和 下一跳地址 preference值越大 优先级越低 一、搭建拓扑结构 二、主机配置 pc1 pc2 三、配置路由器 1.AR1路由器配置 <Huawei>sys #进入系统视图 [Huawei]int g0/0/0 #进入接…

【DevOps】Jenkins 集成Docker

目录 1. 安装 Docker 和 Jenkins 2. 在 Jenkins 中安装 Docker 插件 3. 配置 Docker 连接 4. 创建 Jenkins Pipeline 5. 示例 Pipeline 脚本 6. 运行 Jenkins Job 7. 扩展功能 8、docker配置测试连接的时候报错处理 将 Docker 与 Jenkins 集成可以实现持续集成和持续交…

Java学习第05天-编程思维与编程能力

文章目录 综合应用案例&#xff1a;找素数数组元素的复制数字加密模拟双色球 综合应用 涉及的知识点&#xff1a; 变量、数组运算符&#xff1a;基本运算符、关系运算符、逻辑运算符流程控制&#xff1a;if、switch、for、while、死循环、循环嵌套跳转关键字&#xff1a;break、…

初识C语言——第十一天

操作符&#xff1a; 1. 算数操作符&#xff1a; - * / % 2. 移位操作符&#xff1a; >> &#xff08;右移&#xff09; << &#xff08;左移&#xff09; 移动的是二进制位 例如&#xff1a; int ba<<1; 3. 位操作符&#xff1a; & 按位与 | 按位…

数仓开发:DIM层数据处理

一、了解DIM层 这个就是数仓开发的分层架构 我们现在是在DIM层&#xff0c;从ods表中数据进行加工处理&#xff0c;导入到dwd层&#xff0c;但是记住我们依然是在DIM层&#xff0c;而非是上面的ODS和DWD层。 二、处理维度表数据 ①先确认hive的配置 -- 开启动态分区方案 -- …

Unity技术学习:RenderMesh、RenderMeshInstanced

叠甲&#xff1a;本人比较菜&#xff0c;如果哪里不对或者有认知不到的地方&#xff0c;欢迎锐评&#xff08;不玻璃心&#xff09;&#xff01; 导师留了个任务&#xff0c;渲染大量的、移动的物体。 当时找了几个解决方案&#xff1a; 静态批处理&#xff1a; 这东西只对静…

Springboot+Vue项目-基于Java+MySQL的校园二手书交易平台系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

Netty 网络编程深入学习【一】:ByteBuffer 源码解析

ByteBuffer源码阅读 ByteBuffer是一个用于处理字节数据的缓冲区类。它是Java NIO 包的一部分&#xff0c;提供了一种高效的方式来处理原始字节数据。 ByteBuffer 可以用来读取、写入、修改和操作字节数据&#xff0c;它是一种直接操作字节的方式&#xff0c;比起传统的 InputSt…

如何高速下载,百度 阿里 天翼 等网盘内的内容

如何高速下载&#xff0c;百度 阿里 天翼 等网盘内的内容&#x1f3c5; 前言教程下期更新预报&#x1f3c5; 前言 近段时间经常给大家分享各种视频教程&#xff0c;由于分享的资料是用迅雷网盘存的&#xff0c;但是绝大部分用户都是使用的某度&#xff0c;阿某的这些网盘&…

AI工具大揭秘:如何改变我们的工作和生活

文章目录 &#x1f4d1;前言一、常用AI工具&#xff1a;便利与高效的结合1.1 语音助手1.2 智能推荐系统1.3 自然语言处理工具 二、创新AI应用&#xff1a;不断突破与发展2.1 医疗诊断AI2.2 智能家居2.3 无人驾驶技术 三、AI工具在人们生活中的应用和影响3.1 生活方式的变化3.2 …

旅游系列之:庐山美景

旅游系列之&#xff1a;庐山美景 一、路线二、住宿二、庐山美景 一、路线 庐山北门乘坐大巴上山&#xff0c;住在上山的酒店东线大巴游览三叠泉&#xff0c;不需要乘坐缆车&#xff0c;步行上下三叠泉即可&#xff0c;线路很短 二、住宿 长江宾馆庐山分部 二、庐山美景

Ubuntu 20.04安装桌面XFCE

1.安装Xfce软件包 $ sudo apt update $ sudo apt install xfce42.选择gdm3和lightdm 我这里选择的是lightdm LightDM&#xff0c;即&#xff1a;Light Display Manager&#xff0c;是一个全新的、轻量的Linux桌面的桌面显示管理器&#xff0c;而传统的Ubuntu用的是GNOME桌面…