每天一道算法练习题--Day22 第一章 --算法专题 --- ----------最大公约数

news2024/12/22 20:40:33

关于最大公约数有专门的研究。 而在 LeetCode 中虽然没有直接让你求解最大公约数的题目。但是却有一些间接需要你求解最大公约数的题目。

在这里插入图片描述

如何求最大公约数?

定义法

def GCD(a: int, b: int) -> int:
    smaller = min(a, b)
    while smaller:
        if a % smaller == 0 and b % smaller == 0:
            return smaller
        smaller -= 1

复杂度分析

  • 时间复杂度:最好的情况是执行一次循环体,最坏的情况是循环到 smaller 为 1,因此总的时间复杂度为 O ( N ) O(N) O(N),其中 N 为 a 和 b 中较小的数。
  • 空间复杂度: O ( 1 ) O(1) O(1)

辗转相除法

如果我们需要计算 a 和 b 的最大公约数,运用辗转相除法的话。
首先,我们先计算出 a 除以 b 的余数 c,把问题转化成求出 b 和 c 的最大公约数;
然后计算出 b 除以 c 的余数 d,把问题转化成求出 c 和 d 的最大公约数;
再然后计算出 c 除以 d 的余数 e,把问题转化成求出 d 和 e 的最大公约数。

以此类推,逐渐把两个较大整数之间的运算转化为两个较小整数之间的运算,直到两个数可以整除为止。

def GCD(a: int, b: int) -> int:
    return a if b == 0 else GCD(b, a % b)

在这里插入图片描述

更相减损术

辗转相除法如果 a 和 b 都很大的时候,a % b 性能会较低。在中国,《九章算术》中提到了一种类似辗转相减法的 更相减损术。它的原理是:两个正整数 a 和 b(a>b),它们的最大公约数等于 a-b 的差值 c 和较小数 b 的最大公约数

def GCD(a: int, b: int) -> int:
    if a == b:
        return a
    if a < b:
        return GCD(b - a, a)
    return GCD(a - b, b)

上面的代码会报栈溢出。原因在于如果 a 和 b 相差比较大的话,递归次数会明显增加,要比辗转相除法递归深度增加很多,最坏时间复杂度为 O(max(a, b)))。这个时候我们可以将辗转相除法和更相减损术做一个结合,从而在各种情况都可以获得较好的性能。

形象化解释

下面我们对上面的过程进行一个表形象地讲解,实际上这也是教材里面的讲解方式,我只是照搬过来,增加一下自己的理解罢了。我们来通过一个例子来讲解:

假如我们有一块 1680 米 * 640 米 的土地,我们希望将其分成若干正方形的土地,且我们想让正方形土地的边长尽可能大,我们应该如何设计算法呢?

实际上这正是一个最大公约数的应用场景,我们的目标就是求解 1680 和 640 的最大公约数。

在这里插入图片描述
将 1680 米 * 640 米 的土地分割,相当于对将 400 米 * 640 米 的土地进行分割。 为什么呢? 假如 400 米 * 640 米分割的正方形边长为 x,那么有 640 % x == 0,那么肯定也满足剩下的两块 640 米 * 640 米的。

在这里插入图片描述
在这里插入图片描述

实例解析

题目描述

给你三个数字 a,b,c,你需要找到第 n 个(n 从 0 开始)有序序列的值,
这个有序序列是由 a,b,c 的整数倍构成的。

比如:
n = 8
a = 2
b = 5
c = 7

由于 257 构成的整数倍构成的有序序列为 [1, 2, 4, 5, 6, 7, 8, 10, 12, ...],因此我们需要返回 12。

注意:我们约定,有序序列的第一个永远是 1

大家可以通过 这个网站 在线验证。
一个简单的思路是使用堆来做,唯一需要注意的是去重,我们可以使用一个哈希表来记录出现过的数字,以达到去重的目的。

代码:

ss Solution:
    def solve(self, n, a, b, c):
        seen = set()
        h = [(a, a, 1), (b, b, 1), (c, c, 1)]
        heapq.heapify(h)

        while True:
            cur, base, times = heapq.heappop(h)
            if cur not in seen:
                n -= 1
                seen.add(cur)
            if n == 0:
                return cur
            heapq.heappush(h, (base * (times + 1), base, times + 1))

对于此解法不理解的可先看下我之前写的 几乎刷完了力扣所有的堆题,我发现了这些东西。。。(第二弹)

然而这种做法时间复杂度太高,有没有更好的做法呢?

实际上,我们可对搜索空间进行二分。首先思考一个问题,如果给定一个数字 x,那么有序序列中小于等于 x 的值有几个。
答案是 x // a + x // b + x // c 吗?

// 是地板除

可惜不是的。比如 a = 2, b = 4, n = 4,答案显然不是 4 // 2 + 4 // 4 = 3,而是 2。这里出错的原因在于 4 被计算了两次,一次是 2 ∗ 2 = 4 2 * 2 = 4 22=4,另一次是 4 ∗ 1 = 4 4 * 1 = 4 41=4

为了解决这个问题,我们可以通过集合论的知识。

一点点集合知识:

  • 如果把有序序列中小于等于 x 的可以被 x 整除,且是 a 的倍数的值构成的集合为 SA,集合大小为 A
  • 如果把有序序列中小于等于 x 的可以被 x 整除,且是 b 的倍数的值构成的集合为 SB,集合大小为 B
  • 如果把有序序列中小于等于 x 的可以被 x 整除,且是 c 的倍数的值构成的集合为 SC,集合大小为 C

那么最终的答案就是 SA ,SB,SC 构成的大的集合(需要去重)的中的数字的个数,也就是:
在这里插入图片描述
问题转化为 A 和 B 集合交集的个数如何求?

实际上, SA 和 SB 的交集个数就是 x // lcm(A, B),其中 lcm 为 A 和 B 的最小公倍数。而最小公倍数则可以通过最大公约数计算出来:

def lcm(x, y):
    return x * y // gcd(x, y)

接下来就是二分套路了,二分部分看不懂的建议看下我的二分专题。

代码(Python3):

class Solution:
    def solve(self, n, a, b, c):
        def gcd(x, y):
            if y == 0:
                return x
            return gcd(y, x % y)

        def lcm(x, y):
            return x * y // gcd(x, y)

        def possible(mid):
            return (mid // a + mid // b + mid // c - mid // lcm(a, b) - mid // lcm(b, c) - mid // lcm(a, c) + mid // lcm(a, lcm(b, c))) >= n

        l, r = 1, n * max(a, b, c)
        while l <= r:
            mid = (l + r) // 2
            if possible(mid):
                r = mid - 1
            else:
                l = mid + 1
        return l

在这里插入图片描述

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

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

相关文章

一个集团企业,如何从0到1构建信息化系统?

当今时代&#xff0c;信息技术已经成为企业发展不可或缺的一部分&#xff0c;特别是对于一个大型集团公司来说&#xff0c;如何构建一个高效的信息化系统对于其业务发展至关重要。 我们想要构建一个优质高效的信息化系统&#xff0c;首先需要了解现在大的趋势是怎样的。 目前…

【Linux】Linux安装Java环境(OpenJDK)

文章目录 第一步&#xff1a;第二步&#xff0c;选择合适的版本安装&#xff1a;第四步&#xff0c;配置环境变量 linux环境为CentOS7.8 版本。 今天教大家怎么在CentOs环境中安装Java的开发环境。 在安装java之前我们先来了解一下YUM Yum&#xff08;全称为 Yellow dog Updat…

【JavaEE初阶】简单了解wait和notify方法~

目录 &#x1f31f;1、wait() &#x1f31f;2、notify() &#x1f31f;1、wait() &#xff08;1&#xff09;wait()方法与notify()方法都是Object类中的方法。 &#xff08;2&#xff09;wait()是让线程等待一段时间&#xff0c;死等——>状态WAITING:没有时间限制的等待.…

C++ | 语句的基础知识(夯实基础)

本文概要 本篇文章主要介绍数据结构中C的语句内容&#xff0c;适合有零基础的同学&#xff0c;文中描述和代码示例很详细&#xff0c;干货满满&#xff0c;感兴趣的小伙伴快来一起学习吧&#xff01; &#x1f31f;&#x1f31f;&#x1f31f;个人简介&#x1f31f;&#x1f…

CentOS 7.x 安装 ZooKeeper 并实现集群搭建

0. 集群结构 服务器IPhostname节点说明192.168.31.101master主节点192.168.31.102slave1从节点192.168.31.103 slave2 从节点 下面的安装与配置操作需要在三台服务器上都执行一遍。 1. 安装JDK ZooKeeper要求运行在 JDK 环境上&#xff0c;JDK安装教程可参考 CentOS 7.x 安装…

从点赞到数字货币:揭秘Diem币与Facebook的联系

大家都知道Facebook是一个全球知名的社交媒体平台&#xff0c;但你是否听说过与Facebook有关的数字货币Diem币呢&#xff1f;或许你会想&#xff0c;从点赞到数字货币&#xff0c;这是怎么回事&#xff1f;别着急&#xff0c;让我们一起揭秘Diem币与Facebook的联系。 首先&…

IP一键呼叫语音对讲怎么样?

IP一键呼叫语音对讲怎么样&#xff1f; IP一键呼叫语音对讲&#xff0c;让您的生活更加便利和安全&#xff01; 无需复杂设置&#xff0c;轻松实现远程通话&#xff0c;随时随地与家人朋友沟通交流。APP端可实时监控家庭动态&#xff0c;保证家庭安全。 一键呼叫语音功能&am…

微信小程序——自定义组件

自定义组件 一、组件的创建二、组件的引用1、全局引用2、局部引用 三、全局引用和局部引用 一、组件的创建 第一步&#xff1a;在项目的根目录下创建文件夹components。 第二步&#xff1a;在components文件夹下创建文件夹card。 第三步&#xff1a;选中文件夹card 右键 选中…

openwrt广告屏蔽大师修复补丁luci-app-adbyby plus + lite

openwrt广告屏蔽大师修复补丁 目前使用方式然而有规则无法下载的通病所以可以手工拷贝随便哪里来的规则最后提示 补丁位置 &#xff1a; 地址 http://pan.ezdial.cn/nasone/a 备用&#xff1a;https://bak.ezdial.cn:8000/bakone/a 因什么值得买&#xff0c;在反复审核本文&…

如何在 AlmaLinux 8 上安装和使用 Docker

Docker 是面向开发人员和系统管理员的强大平台&#xff0c;可简化在软件容器内部署应用程序的过程。 容器允许您将应用程序及其所有部分(代码、运行时、系统工具、系统库——通常位于 /usr/bin 或 /usr/lib 中的任何内容)打包&#xff0c;以便它可以在任何 Linux 机器上一致地运…

Linux性能参数调优

内核的shmall和shmmax参数 SHMMAX配置了最大的内存segment的大小&#xff1a;这个设置的比SGA_MAX_SIZE大比较好。 SHMMIN最小的内存segment的大小 SHMMNI整个系统的内存segment的总个数 SHMSEG每个进程可以使用的内存segment的最大个数 配置信号灯&#xff08; semphore …

微软 New Bing, Chat AI 绘图火力全开

嗯&#xff0c;今天的主角是&#xff0c; Microsoft New Bing! 在 Edge 里面&#xff0c;访问 www.bing.com&#xff0c;登录 Microsoft 账户&#xff0c;点击 CHAT, 就可以体验 Bing Chatbot. 这次, New Bing 无需加入 waitlist, 即可全面体验 ChatGPT DALL-E 的绘图功能 关键…

1、防刷限流实现1

1、本章诉求 限流的需求出现在许多常见的场景中&#xff1a; 秒杀活动&#xff0c;有人使用软件恶意刷单抢货&#xff0c;需要限流防止机器参与活动某api被各式各样系统广泛调用&#xff0c;严重消耗网络、内存等资源&#xff0c;需要合理限流 2、流程设计 3、方案实现 3.1…

【致敬未来的攻城狮计划】— 连续打卡第二十二天:RA2E1的RTC时钟日历

系列文章目录 1.连续打卡第一天&#xff1a;提前对CPK_RA2E1是瑞萨RA系列开发板的初体验&#xff0c;了解一下 2.开发环境的选择和调试&#xff08;从零开始&#xff0c;加油&#xff09; 3.欲速则不达&#xff0c;今天是对RA2E1 基础知识的补充学习。 4.e2 studio 使用教程 5.…

XXL-JOB中间件【实现分布式任务调度】

目录 1&#xff1a;XXL-JOB介绍 2&#xff1a;搭建XXL-JOB 2.1&#xff1a;调度中心 2.2&#xff1a;执行器 2.3&#xff1a;执行任务 3&#xff1a;分片广播 1&#xff1a;XXL-JOB介绍 XXL-JOB是一个轻量级分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学…

港科夜闻|广东省委常委、副省长王曦到访香港科技大学

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、广东省委常委、副省长王曦到访香港科技大学。在香港科大校长、粤港澳大湾区院士联盟理事会主席叶玉如教授陪同下&#xff0c;王曦常委率代表团参观国家级科研设施和了解学校发展情况&#xff0c;并与在港中国科学院院士座…

使用MASA全家桶从零开始搭建IoT平台(二)设备注册

前言 我们不希望任何设备都可以接入我们的IoT平台&#xff0c;所以一个设备正常的接入流程是这样的&#xff0c; 1、上位机软件通过串口或其他方式读取设备的唯一标识码UUID。 2、上位机调用IoT后台接口&#xff0c;发送UUID和ProductID。 3、后台接口判断设备是否注册过&…

【JavaEE进阶】——第五节.SpringMVC学习介绍(上)(获取参数,传递参数——关于前后端传参交互的总结、from表单、Ajax数据提交)

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;JavaEE进阶 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01; 目录 文章目…

车载红外夜视「升温」

红外夜视赛道&#xff0c;正在升温。 本周&#xff0c;全球车载后视镜头部供应商Gentex宣布&#xff0c;领投以色列热成像技术初创公司ADASKY&#xff0c;后者在B轮融资中拿到了3000万美元。按照计划&#xff0c;Gentex将协助ADASKY将红外夜视技术推向汽车市场。 事实上&#x…

基于3D网格模型的加密域可逆信息隐藏文献学习

————————————————————————————————————————————— 文献学习&#xff1a; 题目&#xff1a;Separable Reversible Data Hiding Based on Integer Mapping and MSB Prediction for Encrypted 3D Mesh Models. 作者&#xff1a;Na Xu…