动态规划求解第n个丑数:LeetCode 264题详解

发布时间:2026/10/14 14:55:08

动态规划求解第n个丑数:LeetCode 264题详解 1. 问题定义与数学背景丑数Ugly Number是指只包含质因数2、3或5的正整数。LeetCode第264题要求我们找出第n个丑数。这个问题看似简单但蕴含着深刻的数学原理和算法设计思想。从数学角度看丑数序列可以看作是由1开始不断乘以2、3或5生成的数的集合。前几个丑数是1, 2, 3, 4, 5, 6, 8, 9, 10, 12...。值得注意的是7、11、13等不含2、3、5以外质因数的数不属于丑数。关键性质每个丑数都可以表示为2^a × 3^b × 5^c其中a、b、c是非负整数2. 暴力解法与优化思路2.1 直观的暴力解法最直接的思路是对每个正整数依次判断是否为丑数直到找到第n个为止。判断方法是将数字不断除以2、3、5直到无法整除看最终结果是否为1。def is_ugly(num): for p in [2, 3, 5]: while num % p 0: num num // p return num 1 def nthUglyNumber(n): count 0 num 1 while count n: if is_ugly(num): count 1 num 1 return num - 1这种方法的时间复杂度为O(nlogn)对于较大的n如n1690会非常低效因为需要检查大量非丑数。2.2 动态规划解法更高效的解法是利用动态规划。核心思想是每个丑数都是由前面的某个丑数乘以2、3或5得到的。我们需要维护三个指针分别表示下一个丑数是当前指针指向的丑数乘以对应的质因数。def nthUglyNumber(n): ugly [1] i2 i3 i5 0 for _ in range(1, n): next_ugly min(ugly[i2]*2, ugly[i3]*3, ugly[i5]*5) ugly.append(next_ugly) if next_ugly ugly[i2]*2: i2 1 if next_ugly ugly[i3]*3: i3 1 if next_ugly ugly[i5]*5: i5 1 return ugly[-1]这个算法的时间复杂度是O(n)空间复杂度也是O(n)效率显著提升。3. 算法细节与实现技巧3.1 指针移动的逻辑三个指针i2、i3、i5的移动是算法的关键。每次生成新的丑数后所有能产生这个最小值的指针都需要前进这样可以避免重复计算和遗漏。例如当next_ugly6时6 2×3 (i2指向3i3指向2)需要同时移动i2和i3因为3×2和2×3都等于63.2 初始化与边界条件初始丑数列表为[1]因为1被定义为第一个丑数三个指针初始都指向0即第一个丑数需要特别注意n1时的直接返回3.3 空间优化虽然我们使用了O(n)的空间存储丑数序列但实际上可以优化到O(1)空间因为我们只需要保存最近的几个丑数用于比较。不过在大多数实现中保留完整序列更便于理解和调试。4. 数学证明与正确性验证4.1 算法正确性证明动态规划解法的正确性基于以下两个性质每个丑数除1外都可以表示为较小丑数乘以2、3或5通过维护三个指针我们确保每个乘积都被考虑到且按顺序生成4.2 数学归纳法验证基础情况第一个丑数1正确 归纳假设前k个丑数正确生成 归纳步骤第k1个丑数是min(ugly[i2]*2, ugly[i3]*3, ugly[i5]*5)由归纳假设这三个乘积都是基于正确的丑数生成的且取最小值保证了顺序正确5. 性能分析与优化5.1 时间复杂度对比方法时间复杂度空间复杂度适用场景暴力法O(nlogn)O(1)小规模n动态规划O(n)O(n)通用堆/优先队列O(nlogn)O(n)需要按序生成时5.2 实际运行测试当n1690时暴力法约5秒Python实现动态规划1毫秒5.3 进一步优化思路预计算如果需要多次查询可以预先生成一个足够大的丑数列表数学方法利用丑数的数学性质推导公式但实现复杂并行计算将生成过程分解为独立任务并行执行6. 常见错误与调试技巧6.1 典型错误案例指针移动不全只移动一个指针而忽略其他可能产生相同最小值的指针初始条件错误忘记包含1作为第一个丑数整数溢出当n很大时丑数可能超出整数范围Python无此问题6.2 调试方法打印中间结果输出生成的丑数序列和指针位置小规模测试先验证n10等小规模的正确性边界检查特别测试n1和n2的情况6.3 测试用例设计test_cases [ (1, 1), (2, 2), (10, 12), (20, 36), (1690, 2123366400) ]7. 实际应用与扩展7.1 现实中的应用场景资源分配如任务调度中优先处理简单任务类比丑数的优先级密码学在某些哈希算法中需要生成特定性质的数字游戏开发需要生成特定倍数的分数或奖励7.2 问题变种超级丑数质因数不限于2、3、5而是给定的一组质数丑数II判断一个数是否为丑数按序生成实时生成丑数序列而不预先知道n7.3 扩展思考如何证明丑数序列在正整数集中的密度为0能否找到第n个丑数的闭式表达式如何高效生成前n个丑数的所有质因数分解8. 不同语言实现对比8.1 Python实现特点利用动态数组和min函数使代码简洁def nthUglyNumber(n): ugly [1] i2 i3 i5 0 for _ in range(n-1): u2, u3, u5 ugly[i2]*2, ugly[i3]*3, ugly[i5]*5 umin min(u2, u3, u5) if umin u2: i2 1 if umin u3: i3 1 if umin u5: i5 1 ugly.append(umin) return ugly[-1]8.2 Java实现注意事项需要显式类型声明和数组初始化public int nthUglyNumber(int n) { int[] ugly new int[n]; ugly[0] 1; int i2 0, i3 0, i5 0; for (int i 1; i n; i) { int next Math.min(ugly[i2]*2, Math.min(ugly[i3]*3, ugly[i5]*5)); ugly[i] next; if (next ugly[i2]*2) i2; if (next ugly[i3]*3) i3; if (next ugly[i5]*5) i5; } return ugly[n-1]; }8.3 C实现性能优化可以使用vector并注意避免重复计算int nthUglyNumber(int n) { vectorint ugly(n); ugly[0] 1; int i2 0, i3 0, i5 0; for (int i 1; i n; i) { int u2 ugly[i2] * 2; int u3 ugly[i3] * 3; int u5 ugly[i5] * 5; ugly[i] min(u2, min(u3, u5)); if (ugly[i] u2) i2; if (ugly[i] u3) i3; if (ugly[i] u5) i5; } return ugly.back(); }9. 算法可视化理解为了更好理解动态规划解法可以想象有三个队列Q2存储每个丑数×2的结果Q3存储每个丑数×3的结果Q5存储每个丑数×5的结果每次取三个队列头部的最小值作为下一个丑数并将对应的队列指针后移。这种方法避免了排序保证了顺序性。10. 面试技巧与回答策略当面试中被问到这个问题时建议采取以下步骤先明确问题定义和要求提出暴力解法并分析其复杂度指出暴力解法的问题效率低提出动态规划思路并解释三个指针的作用逐步推导算法实现分析时间/空间复杂度讨论可能的优化和变种典型面试问题可能包括如何证明你的算法是正确的如果不允许使用额外空间如何解决如果质因数不限于2、3、5而是任给的如何修改算法在实际编码时我发现最容易出错的地方是三个指针的更新条件。有一次我在白板面试中忘记了同时更新能产生相同最小值的所有指针导致生成的序列缺少某些丑数。这个教训让我更加理解了每个指针独立移动的重要性。
延伸阅读

更多相关文章

2026/10/14 14:55:08

CTF逆向工程:RC4加密与Unicode编码陷阱解析

1. 逆向工程中的编码陷阱解析这道CTF题目表面看似简单的RC4加解密,实则暗藏了多个编码层面的陷阱。我们先从文件结构分析入手,用IDA Pro加载程序后发现主要逻辑集中在main函数和两个关键子函数:加密函数sub_401005和解密函数sub_401080。程序…

2026/10/14 14:50:05

USRP扫频实时频谱分析:C++实现、线程模型与工程避坑指南

简介:一套面向软件无线电开发者与通信工程学习者的完整项目源码,围绕USRP平台实现扫频信号实时频谱分析,涵盖USRP驱动配置、扫频循环、功率谱密度计算及频谱图实时显示,并聚焦C/C底层控制与优化技巧。压缩包共336个文件&#xff0…

2026/10/14 14:50:05

C#订单管理系统实战:状态机、并发控制与避坑指南

简介:C#订单管理系统是一份面向.NET初学者及中级开发者的完整项目资料,覆盖企业订单处理中数据访问、业务逻辑、界面呈现、异常捕获与并发控制等核心环节,整体采用分层结构组织代码,便于理解与二次开发。资源包为rar格式&#xff…

2026/10/14 16:15:41

飞行路径优化:从燃油模型到MATLAB落地全解析

简介:一套面向航空路径规划与燃油效率优化的开源代码包,聚焦亚特兰大至西雅图的最佳航线求解。项目利用历史航路点数据,结合最短路径算法模拟燃料消耗,在MATLAB与Python环境下完成天气数据获取、可行网络构建与候选路径评估&#…

2026/10/14 16:15:41

Linux内核学习导航地图:问题驱动的实战入门路径

1. 这不是一份普通目录,而是一张Linux内核探索的导航地图“【Linux 内核专栏 00】总目录”——看到这个标题,很多人第一反应是:又一个空泛的索引页?点进去怕不是只有几行链接加一句“敬请期待”?但如果你真这么想&…

2026/10/14 16:15:41

诺威达K2201卡刷包:嵌入式固件升级的硬件级精准操作指南

简介:本资源是专为诺威达K2201-NWD系列车机用户提供的2019年3月发布的官方风格卡刷固件包,适用于希望升级系统、修复稳定性问题或个性化定制界面的中级以上车机爱好者与售后技术人员。刷机后可更换主题(主题密码111333)&#xff0…

2026/10/14 16:15:41

Liquibase数据库版本管理:从入门到生产就绪

1. 为什么 Liquibase 不是“又一个数据库迁移工具”,而是团队协作的底层契约你有没有遇到过这样的场景:开发在本地把 user 表加了 email 字段,测试环境跑得好好的,上线前 DBA 突然说“这个字段名和生产已有视图冲突”,…

2026/10/14 16:15:41

数据库安全性设计:权限分层、加密编排与可信备份体系

1. 数据库安全不是“加把锁”就完事:从一次权限误配引发的连锁反应说起我第一次真正意识到数据库安全不是教科书里那几行“用户认证、访问控制、审计日志”的定义,是在一个模拟项目X的压测阶段。当时系统刚完成基础功能联调,某导师在演示环境…

2026/10/14 16:10:37

LightGBM自定义F1评测与Focal Loss损失函数实战指南

1. 为什么LightGBM原生不支持F1 Score,却还要费劲写自定义函数?LightGBM在工业级模型训练中被广泛使用,不是因为它“最先进”,而是它在精度、速度、内存占用三者之间找到了极难复制的平衡点。但它的设计哲学很务实:只内…

2026/10/14 11:31:03

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/13 17:09:18

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/14 2:32:55

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/14 0:00:33

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:33

macOS/iOS高精度计时:mach_absolute_time原理与实战

1. 项目概述:为什么mach_absolute_time是 macOS/iOS 时间测量的“黄金标准”在 macOS 和 iOS 开发中,我见过太多人用CFAbsoluteTimeGetCurrent()或NSDate.timeIntervalSinceReferenceDate做性能打点,结果在高精度场景下被系统时钟跳变、NTP 同…

2026/10/14 0:00:33

SCORM课件演示与测试全解析:从API通信到自动化验证

简介:这是一套遵循SCORM标准的交互式课件演示与测试资源,面向E-Learning课程开发者、LMS平台测试人员及在线教学从业者,用于验证课件在不同学习管理系统中的识别、传递与跟踪能力。压缩包共28个文件,约12.07MB,以swf动…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑