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:第一个想法是直接全量替换,事实证明这样不行,会很卡顿,有明显闪烁感,如果标记点比较少,就十几个可以用…

嵌入式学习——数据结构——顺序表

线性表的定义 线性表是零个或多个数据元素的有限序列&#xff0c;元素之间具有顺序性&#xff0c;如果存在多个元素&#xff0c;第一个元素无前驱&#xff0c;最有一个没有后继&#xff0c;其他的元素只有一个前驱和一个后继。线性表元素的个数n&#xff08;n>0&#xff09…

QT如何在对话框中插入表格

在Qt中&#xff0c;如果你想要在对话框中插入表格&#xff0c;通常会使用QTableWidget或QTableView结合QStandardItemModel&#xff08;对于QTableView&#xff09;或直接在QTableWidget中操作。这里&#xff0c;我将介绍如何使用QTableWidget在对话框中插入表格&#xff0c;因…

【网络安全】-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…

windows安装docker并初始化dapr

现在安装docker假如启动报错WSL2.0 bcdedit /set hypervisorlaunchtype auto重启电脑安装dapr winget install Dapr.CLIdapr init dapr init确认init成功 docker ps确定components文件夹init成功 %UserProfile%\.dapr

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

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

MongoDB 的功能

MongoDB 是一个开源的、面向文档的 NoSQL 数据库管理系统&#xff0c;具有高性能、可扩展性和灵活的存储结构。与传统的关系型数据库不同&#xff0c;MongoDB 使用 JSON 类似的 BSON&#xff08;Binary JSON&#xff09;格式存储数据&#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。 这题来简单抽象…

架构师考试系列(1)论文专题:基于构件的软件开发方法

摘要&#xff1a; 本文以我主持开发的某公司企业信息管理系统为例&#xff0c;探讨了基于构件的软件开发问题。该系统是一个综合信息系统&#xff0c;涵盖了原料采购、生产管理、物流管控等七大功能。在开发过程中&#xff0c;我担任系统架构师&#xff0c;负责需求分析、系统建…

常用Java API

1 字符串处理 1.1 String 类 String 类是 Java 中不可变的字符序列。它提供了以下常用方法&#xff1a; length()&#xff1a;返回字符串的长度。 charAt(index)&#xff1a;返回指定索引处的字符。 substring(startIndex, endIndex)&#xff1a;返回从 startIndex 到 endI…

物联网之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…

软件测试工程师面试整理-测试类型

软件测试类型多种多样,涵盖了从功能验证到性能评估的不同方面。了解各种测试类型有助于在软件开发生命周期的不同阶段选择合适的测试方法,确保软件的质量和可靠性。以下是常见的软件测试类型: 1. 功能测试(Functional Testing) ● 目标:验证软件功能是否按照需求文档正确…

2024年9月HarmonyOS鸿蒙应用开发者高级认证全新题库(覆盖99%考题)

一个小时通过鸿蒙高级认证 1、在开发 Harmony0S 应用工程时&#xff0c; 随着业务的发展&#xff0c;现在需要创建一个模块&#xff0c; 关于在 DevEco Studio 中创建 Module &#xff0c; 下列选项哪种方式是错误的? 必对 在 hvigor 目录下&#xff0c;单击鼠标右键&#xf…

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

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