Python面试宝典第48题:找丑数

题目

        我们把只包含质因子2、3和5的数称作丑数(Ugly Number)。比如:6、8都是丑数,但14不是,因为它包含质因子7。习惯上,我们把1当做是第一个丑数。求按从小到大的顺序的第n个丑数。

        示例 1:

输入:5
输出:5

        示例 2:

输入:7
输出:8

暴力法

        本题最直观的解法是使用暴力法,即从1开始逐个检查每个自然数是否为丑数,直到找到第n个丑数为止。使用暴力法求解本题的主要步骤如下。

        1、定义一个函数,用于判断一个数是否为丑数。

        2、从1开始遍历每一个数,对每个数调用该函数。

        3、计数器记录已经找到的丑数的数量,当计数器达到n时,返回当前检查的数作为第n个丑数。

        根据上面的算法步骤,我们可以得出下面的示例代码。

def is_ugly_number(num):if num <= 0:return Falsefor factor in [2, 3, 5]:while num % factor == 0:num //= factorreturn num == 1def find_ugly_numbers_by_brute_force(n):count = 0num = 1while True:if is_ugly_number(num):count += 1if count == n:return numnum += 1print(find_ugly_numbers_by_brute_force(5))
print(find_ugly_numbers_by_brute_force(7))

优先队列法

        优先队列法利用了最小堆的数据结构来保持未处理的丑数候选,其基本思想为:初始时,我们将1加入到优先队列中,因为1是最小的丑数;之后,每次从队列中取出最小的元素,并将其与2、3、5相乘后再次加入队列中。为了避免重复加入相同的丑数,我们需要记录之前加入队列的最大值,并确保不加入小于等于该最大值的数。使用优先队列法求解本题的主要步骤如下。

        1、初始化堆和已知丑数。

        (1)创建一个最小堆heap,并向其中添加第一个丑数1。

        (2)创建一个集合seen,用于存储已经发现的丑数,以防止重复计算。

        (3)设置变量last_ugly为 1,这代表最后加入的丑数。

        (4)设置计数器count为 1,用来跟踪已经找到的丑数的数量。

        2、循环直到找到第n个丑数,并执行以下操作。

        (1)每次循环从堆中弹出最小的丑数current,并使用三个质因数(2、3、5)分别乘以current来生成新的丑数。

        (2)对于每个新生成的丑数new_ugly,检查它是否已经被计算过,即是否存在于seen集合中。

        (3)如果new_ugly还未被计算过,则将其添加到seen集合中,并将其推入堆heap中。

        3、更新最后加入的丑数。

        (1)如果弹出的丑数current不等于last_ugly,这意味着我们找到了一个新的丑数。

        (2)更新last_ugly为current,并将count加一。

        (3)当count达到n时,循环结束,此时last_ugly即为第n个丑数。

        4、返回last_ugly作为第n个丑数。

        根据上面的算法步骤,我们可以得出下面的示例代码。

import heapqdef find_ugly_numbers_by_priority_queue(n):# 初始化最小堆heap = [1]# 记录最后一个加入堆的丑数last_ugly = 1# 已找到的丑数数量count = 1# 使用集合来去重seen = set([1])while count < n:# 弹出当前最小的丑数current = heapq.heappop(heap)# 生成新的丑数并加入堆中for factor in [2, 3, 5]:new_ugly = current * factor# 如果新生成的丑数还没有被加入过,则加入堆中if new_ugly not in seen:seen.add(new_ugly)heapq.heappush(heap, new_ugly)# 只有在当前丑数不等于最后一个加入的丑数时,才进行下一步操作if current != last_ugly:last_ugly = currentcount += 1# 最后一个加入的丑数就是第n个丑数return last_uglyprint(find_ugly_numbers_by_priority_queue(5))
print(find_ugly_numbers_by_priority_queue(7))

动态规划法

        使用动态规划法的关键是:定义状态转移方程。假设dp[i]表示第i个丑数,则本题的状态转移方程为:dp[i] = min(2 * dp[j], 3 * dp[k], 5 * dp[l])。其中,j、k、l分别表示最近乘以2、3、5得到dp[i]的索引。边界条件为dp[1] = 1,因为1是最小的丑数。使用动态规划法求解本题的主要步骤如下。

        1、初始化数组dp,长度为n + 1,其中dp[1] = 1。

        2、定义三个指针j、k、l,初始值均为1。

        3、对于每个i(从2到n),进行以下操作。

        (1)计算dp[i]的值,它是2 * dp[j]、3 * dp[k]、5 * dp[l]中的最小值。

        (2)如果dp[i]等于2 * dp[j],则j加1。

        (3)如果dp[i]等于3 * dp[k],则k加1。

        (4)如果dp[i]等于5 * dp[l],则l加1。

        4、当i达到n时,dp[n]就是第n个丑数。

        根据上面的算法步骤,我们可以得出下面的示例代码。

def find_ugly_numbers_by_dp(n):if n == 1:return 1# 初始化dp数组dp = [0] * (n + 1)dp[1] = 1j, k, l = 1, 1, 1for i in range(2, n + 1):# 计算下一个丑数dp[i] = min(2 * dp[j], 3 * dp[k], 5 * dp[l])# 更新指针if dp[i] == 2 * dp[j]:j += 1if dp[i] == 3 * dp[k]:k += 1if dp[i] == 5 * dp[l]:l += 1return dp[n]print(find_ugly_numbers_by_dp(5))
print(find_ugly_numbers_by_dp(7))

总结

        暴力法的实现较为简单,但效率低下,尤其是在n较大的时候。最坏情况下,需要检查所有的数直到找到第n个丑数。假设第n个丑数是u(n),则暴力法的时间复杂度为O(u(n))。其空间复杂度为O(1),只需要常数级别的额外空间。

        使用优先队列法时,插入和删除操作的时间复杂度为O(logu(n)),且需要做n次这样的操作,故总的时间复杂度为O(n*logu(n))。堆的大小最多为u(n),故总的空间复杂度为O(u(n))。与暴力法相比,优先队列法的效率更高,但可能带来较多的空间消耗。

        使用动态规划法时,每个数只被访问一次,故时间复杂度为O(n)。其空间复杂度也为O(n),因为仅需要一个长度为n的数组来存储结果。动态规划法在时间和空间上都较为平衡,故实际应用中,通常倾向于使用动态规划法来解决这类问题。

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

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

相关文章

基于MinerU的PDF解析API

基于MinerU的PDF解析API - MinerU的GPU镜像构建 - 基于FastAPI的PDF解析接口支持一键启动&#xff0c;已经打包到镜像中&#xff0c;自带模型权重&#xff0c;支持GPU推理加速&#xff0c;GPU速度相比CPU每页解析要快几十倍不等 主要功能 删除页眉、页脚、脚注、页码等元素&…

uniapp使用高德地图设置marker标记点,后续根据接口数据改变某个marker标记点,动态更新

最近写的一个功能属实把我难倒了,刚开始我请求一次数据获取所有标记点,然后设置到地图上,然后后面根据socket传来的数据对这些标记点实时更新,改变标记点的图片或者文字, 1:第一个想法是直接全量替换,事实证明这样不行,会很卡顿,有明显闪烁感,如果标记点比较少,就十几个可以用…

【网络安全】-rce漏洞-pikachu

rce漏洞包含命令执行漏洞与代码执行漏洞 文章目录 前言 什么是rce漏洞&#xff1f; 1.rce漏洞产生原因&#xff1a; 2.rce的分类&#xff1a; 命令执行漏洞&#xff1a; 命令拼接符&#xff1a; 常用函数&#xff1a; 代码执行漏洞&#xff1a; 常用函数&#xff1a; 分类&…

信号与线性系统综合实验

文章目录 一、实验目的二、实验内容及其结果分析&#xff08;一&#xff09;基础部分&#xff08;二&#xff09;拓展部分&#xff08;三&#xff09;应用设计部分 三、心得体会 一、实验目的 1、掌握连续时间信号与系统的时域、频域综合分析方法&#xff1b;   2、掌握运用M…

SAP B1 单据页面自定义 - 用户界面编辑字段

背景 接《SAP B1 基础实操 - 用户定义字段 (UDF)》&#xff0c;在设置完自定义字段后&#xff0c;如下图&#xff0c;通过打开【用户定义字段】可打开表单右侧的自定义字段页。然而再开打一页附加页面操作繁复&#xff0c;若是客户常用的定义字段&#xff0c;也可以把这些用户…

JMM 指令重排 volatile happens-before

在单线程程序中&#xff0c;操作系统会通过编译器优化重排序、指令级并行重排序、内存系统重排序三个步骤对源代码进行指令重排&#xff0c;提高代码执行的性能。 但是在多线程情况下&#xff0c;操作系统“盲目” 地进行指令重排可能会导致我们不想看到的问题&#xff0c;如经…

2024第三届大学生算法大赛 真题训练2 解题报告 | 珂学家 | FFT/NTT板子

前言 题解 D是FFT板子题&#xff0c;这么来看&#xff0c;其实处于ACM入门题&#xff0c;哭了T_T. D. 行走之谜 思路: FFT 如果你知道多项式乘法&#xff0c;继而知道FFT&#xff0c;那题纯粹就是板子题&#xff0c;可惜当时比赛的时候&#xff0c;无人AC。 这题来简单抽象…

物联网之PWM呼吸灯、脉冲、LEDC

MENU 前言原理硬件电路设计软件程序设计analogWrite()函数实现呼吸灯效果LEDC输出PWM信号 前言 学习制作呼吸灯&#xff0c;通过LED灯的亮度变化来验证PWM不同电压的输出。呼吸灯是指灯光在单片机的控制之下完成由亮到暗的逐渐变化&#xff0c;感觉好像是人在呼吸。 原理 脉冲宽…

【中秋月饼系列】2024年立体月饼新鲜出炉----python画月饼(1)附完整代码

【中秋月饼系列】2024年立体月饼新鲜出炉 ----python画月饼&#xff08;1&#xff09;附完整代码 本文目录&#xff1a; 零、时光宝盒 一、2024年中秋节立体逼真月饼&#xff08;效果展示&#xff09; 二、Python 海龟画图主要方法 &#xff08;1&#xff09;海龟画图的主…

学习大数据DAY56 业务理解和第一次接入

作业1 1 了解行业名词 ERP CRM OA MES WMS RPA SAAS 了解每个系统的功能和应用 ERP 系统&#xff0c;&#xff08;Enterprise Resource Planning&#xff0c;企业资源计划系统&#xff09;&#xff1a;ERP 系统 是一种用于管理企业各类资源的软件系统&#xff0c;包括生产管理…

攻防世界 ics-05

ics-05 隐藏的变量传参&#xff0c;php弱类型比较 只有设备维护中心可以点击进去 查看源码&#xff0c;发现有个隐藏的超链接变量传参 看到变量传参&#xff0c;有可能存在文件包含漏洞读取源码&#xff0c;这个站是php的站&#xff0c;所以可以使用php伪协议读取源码 index.p…

Docker Swarm管理(Docker技术集群与应用)

如上图所示&#xff0c; 三台主机&#xff1a;恢复到docker的快照&#xff1b; 然后上传到三台服务器所需的镜像&#xff1b; 同步会话。执行导入脚本将镜像导入到系统中&#xff1b; 然后取消会话的同步&#xff0c;设置各个主机的主机名&#xff1b; 然后同步会话修改hosts…

Java JUC(一) 线程概念与常用方法

Java JUC&#xff08;一&#xff09; 线程概念与常用方法 一. JUC 基本概念 Java JUC&#xff08;Java Util Concurrent&#xff09; 是Java平台提供的一个并发编程工具包&#xff08;java.util.concurrent&#xff09;&#xff0c;全称为Java Concurrency Utilities。这个工具…

深入剖析 MQTT 协议:物联网通信的核心力量

摘要&#xff1a; 本文全面深入地探讨了 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;协议。详细阐述了 MQTT 协议的起源与发展背景&#xff0c;介绍其基本概念、特点及工作原理。深入分析了 MQTT 的架构组成&#xff0c;包括客户端、代理服务器及主题的作…

Jenkins部署若依项目

一、配置环境 机器 jenkins机器 用途&#xff1a;自动化部署前端后端&#xff0c;前后端自动化构建需要配置发送SSH的秘钥和公钥&#xff0c;同时jenkins要有nodejs工具来进行前端打包&#xff0c;maven工具进行后端的打包。 gitlab机器 用途&#xff1a;远程代码仓库拉取和…

基于Linux的ARMxy工控机IEC61850协议实践

工业自动化水平的不断提高&#xff0c;对设备间高效、可靠通信的需求日益增长。IEC61850标准作为电力系统自动化领域的重要国际标准之一&#xff0c;其应用范围正在从传统的电力行业向更广泛的工业自动化领域扩展。本文将探讨基于ARM架构的工业计算机如何在Linux操作系统环境下…

解码未来:H.265与H.266技术对比及EasyCVR视频汇聚平台编码技术优势

随着视频技术的不断发展&#xff0c;视频编码标准也在不断更新迭代。H.265&#xff08;也称为HEVC&#xff0c;High Efficiency Video Coding&#xff09;和H.266&#xff08;也称为VVC&#xff0c;Versatile Video Coding&#xff09;作为当前和未来的主流视频编码标准&#x…

BrainSegFounder:迈向用于神经影像分割的3D基础模型|文献速递--Transformer架构在医学影像分析中的应用

Title 题目 BrainSegFounder: Towards 3D foundation models for neuroimagesegmentation BrainSegFounder&#xff1a;迈向用于神经影像分割的3D基础模型 01 文献速递介绍 人工智能&#xff08;AI&#xff09;与神经影像分析的融合&#xff0c;特别是多模态磁共振成像&am…

【机器学习】马尔可夫随机场的基本概念、和贝叶斯网络的联系与对比以及在python中的实例

引言 马尔可夫随机场&#xff08;Markov Random Field&#xff0c;简称MRF&#xff09;是一种用于描述变量之间依赖关系的概率模型&#xff0c;它在机器学习和图像处理等领域有着广泛的应用 文章目录 引言一、马尔科夫随机场1.1 定义1.2 特点1.3 应用1.4 学习算法1.5 总结 二、…

【数据分析预备】Pandas

Pandas 构建在NumPy之上&#xff0c;继承了NumPy高性能的数组计算功能&#xff0c;同时提供更多复杂精细的数据处理功能 安装 pip install pandas导入 import pandas as pdSeries 键值对列表 # 创建Series s1 pd.Series([5, 17, 3, 26, 31]) s10 5 1 17 2 3 3 26 4 31 dt…