当前位置: 首页 > news >正文

Leetcode 剑指 Offer II 168. 丑数

题目难度: 中等

原题链接

今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号算法精选里回复剑指offer2就能看到该系列当前连载的所有文章了, 记得关注哦~

题目描述

给你一个整数 n ,请你找出并返回第 n 个 丑数 。

说明:丑数是只包含质因数 2、3 和/或 5 的正整数;1 是丑数。

示例 1:

  • 输入: n = 10
  • 输出: 12
  • 解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。

提示:

  • 1 <= n <= 1690

题目思考

  1. 如何从当前的丑数得到后面的丑数?
  2. 如何保证从小到大?

解决方案

方案 1

思路
  • 一个比较容易想到的思路是使用一个小顶堆, 每次从堆顶 pop 出当前最小的丑数, 然后乘以 2/3/5 得到新丑数, 如果新丑数没有在堆中的话, 就将其加入堆中
  • 这样 pop n 次即为第 n 个丑数
  • 判断新丑数是否存在, 可以额外使用一个集合, 这样判断存在性就只需要 O(1)
  • 显然初始化堆和集合中的元素都是 1, 代表第 1 个丑数
  • 以上的操作是不是很类似 BFS 的思路? 不同的是这里利用了堆而不是双端队列/列表来处理当前的元素, 所以举一反三很重要
复杂度
  • 时间复杂度 O(NlogN): 共需要 N 次堆操作, 每次堆操作的时间复杂度是 logN
  • 空间复杂度 O(N): 使用了一个小顶堆和一个集合
代码
classSolution:defnthUglyNumber(self,n:int)->int:# 初始化集合和堆中元素都为1v={1}q=[1]foriinrange(n):res=heapq.heappop(q)forfactorin(2,3,5):nex=res*factorifnexnotinv:# 新丑数没在堆里的话, 将其加入堆中v.add(nex)heapq.heappush(q,nex)returnres

方案 2

思路
  • 回顾方案 1, 因为引入了堆, 所以时间复杂度达到了 O(NlogN), 那有没有更优的方案呢, 比如 O(N) 时间复杂度?
  • 答案也是有的, 我们重新分析题目, 要求数字的质因子只有 2/3/5, 我们就可以把当前丑数乘以 2/3/5 的数字分别存入三个数组中, 并将 1 作为第 1 个值, 这样就可以将题目转换成将三个有序数组进行合并去重后求第 n 个最小值
    • arr2 = [1*2, 2*2, 3*2, 4*2, 5*2, 6*2, 8*2, ...] (注意7不是丑数)
    • arr3 和 arr5 类似, 只是把乘数改成了 3 和 5
  • 为什么需要去重呢?举个例子, 对于 6, 它既存在于 arr2 中, 也存在于 arr3 中
  • 如何合并去重呢?我们可以维护 3 个指针, 分别对应这三个数组遍历到的元素位置, 那么当前最小值自然就是 3 个元素中最小的那个了, 然后将最小元素对应的指针后移(可能会遇到最小值不止一个, 这个时候移动的指针也不止一个), 继续判断即可
  • 需要保存哪些数组呢?注意 arr2/arr3/arr5 有个共同特点是作为因子的丑数序列是相同的, 都是[1,2,3,4,5,6,8,...], 只是需要乘的质因子不同. 所以我们并没有必要真正保存 3 个数组, 而只需要保存升序丑数序列即可, 这样恰好该序列的第 n 个数就是最终结果.而 arr2/arr3/arr5 只需要在该丑数序列基础上乘以 2/3/5 即可得到, 然后三个数组的指针移动还和上面的分析一样
  • 下面的代码对必要步骤有详细的注释, 方便大家理解
复杂度
  • 时间复杂度 O(N): 只需要遍历一遍
  • 空间复杂度 O(N): 额外使用了一个数组存升序丑数序列
代码
classSolution:defnthUglyNumber(self,n:int)->int:# 初始化丑数序列第一个元素为1ugly=[1]# 初始化arr2/arr3/arr5的下标都为0i2,i3,i5=0,0,0whilelen(ugly)<n:# 取arr2/arr3/arr5三者中的最小值追加到当前升序丑数序列中# 根据下面三个if判断的逻辑, 新追加的值一定大于之前丑数序列的最大值(最后一个值), 因为之前的最大值若等同于arr2/arr3/arr5的下标对应的值的话, 会将下标+1的, 新下标的值一定大于原下标的ugly.append(min(2*ugly[i2],3*ugly[i3],5*ugly[i5],))ifugly[-1]==2*ugly[i2]:# 最小值和arr2下标的值*2一样, i2加1i2+=1ifugly[-1]==3*ugly[i3]:# 同上i3+=1ifugly[-1]==5*ugly[i5]:# 同上i5+=1returnugly[-1]

大家可以在下面这些地方找到我~😊

我的 GitHub

我的 Leetcode

我的 CSDN

我的知乎专栏

我的头条号

我的牛客网博客

我的公众号: 算法精选, 欢迎大家扫码关注~😊

http://www.jsqmd.com/news/633509/

相关文章:

  • [特殊字符]HistoXGAN有没有人复现过这个[特殊字符]
  • CYBER-VISION零号协议Python环境配置常见问题一站式解决
  • WarcraftHelper 终极指南:让经典魔兽争霸3在现代系统完美运行
  • 探讨有实力的实验室前处理设备厂家,哪家口碑好价格又合理 - myqiye
  • 告别盲调!用VOFA+和STM32F407的串口状态机,实现PID参数实时可视化调整
  • WorkshopDL:跨平台Steam创意工坊下载神器,无需Steam客户端即可畅享海量模组
  • FireRed-OCR Studio实操手册:批量文档解析API接口封装示例
  • FanControl终极指南:5分钟打造智能风扇控制系统,告别PC噪音与过热烦恼
  • 2026 国产高端 EDA 工具测评:好用稳定款推荐 - 品牌2026
  • Easy MFRC522驱动开发指南:嵌入式RFID读写实战
  • 企业实力与产品矩阵:宁波普瑞思在磁性材料分析仪及RoHS检测领域的深耕之路 - 品牌推荐大师
  • 如何用高斯马尔可夫随机场(GMRF)解决空间统计中的‘大n问题‘?
  • 实测Qwen3字幕生成:上传MP3,1分钟输出带时间戳的SRT文件
  • Context Engineering(上下文工程)
  • 新手工程师必看:用Altium Designer搞定PCB布局布线的5个实战技巧(附DRC检查清单)
  • MySQL 查询优化器执行计划分析
  • 智能办公利器:STEP3-VL-10B多模态模型如何帮你分析PPT报告中的图文数据
  • 如何用HsMod插件解锁炉石传说的个性化游戏体验
  • 告别模糊图像:html-to-image 像素比率(Pixel Ratio)完全控制指南
  • 2026 国产 EDA 工具推荐:国产全流程 EDA 软件哪个好? - 品牌2026
  • 深入解析Oracle数据泵任务监控与状态追踪
  • Qwen3.5-9B脑科学:fMRI图像描述+认知实验设计+神经机制解释生成
  • 过程决策程序图管理化技术中的过程决策程序图计划过程决策程序图实施过程决策程序图验证
  • 合并两个有序链表
  • Linux System V 信号量详解与进程同步实战
  • html-docx-js:浏览器端HTML到DOCX转换的架构实现与深度集成方案
  • 药用级环拉酸钠哪家便宜 高性价比供应商推荐 - 品牌推荐大师
  • 终极指南:如何用sndcpy实现Android音频无线转发到电脑
  • Qwen3.5-9B企业应用:HR招聘JD生成+候选人简历匹配度分析案例
  • Janus-Pro-7B开发环境配置详解:从IDEA安装到调试插件集成