动态规划解决丑数问题:原理与实现

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

动态规划解决丑数问题:原理与实现 1. 丑数问题背景与定义丑数Ugly Number是算法领域中一个经典的数字分类问题。根据数学定义丑数是指只包含质因数2、3或5的正整数。换句话说如果一个正整数可以被分解为若干个2、3或5的乘积那么这个数就是丑数。例如数字6可以分解为2×3因此它是丑数而数字14由于包含质因数7所以不是丑数。这个问题最早出现在编程竞赛和算法面试中后来被Leetcode收录为第264题。题目通常要求我们找出第n个丑数其中n由用户指定。例如当n10时我们需要返回第10个丑数12丑数序列1, 2, 3, 4, 5, 6, 8, 9, 10, 12...。2. 问题分析与解决思路2.1 暴力解法及其局限性最直观的解决方法是遍历所有正整数逐个检查是否为丑数直到找到第n个为止。这种方法虽然简单但效率极低。对于每个数字m我们需要不断除以2、3、5直到无法整除为止然后判断剩余数字是否为1。这种方法的复杂度约为O(nlogn)当n较大时如n1690计算时间会变得不可接受。2.2 动态规划解法原理更高效的解决方案是使用动态规划。我们可以利用已知的丑数来生成新的丑数而不是逐个检查每个数字。核心思路是每个丑数都可以由更小的丑数乘以2、3或5得到。我们需要维护三个指针分别对应2、3、5的倍数每次选择最小的候选数作为下一个丑数并更新相应的指针。这种方法的时间复杂度为O(n)空间复杂度也是O(n)因为我们需要存储前n个丑数。相比暴力解法效率提升显著特别适合处理较大的n值。3. 动态规划实现详解3.1 算法步骤拆解初始化创建数组dp存储丑数dp[0]1第一个丑数初始化三个指针i2、i3、i5都指向dp[0]循环计算从dp[1]到dp[n-1]计算三个候选数next2dp[i2]*2, next3dp[i3]*3, next5dp[i5]*5选择三者中最小的作为下一个丑数dp[i]更新对应指针如果dp[i]next2则i2同理处理i3和i5返回dp[n-1]3.2 代码实现示例def nthUglyNumber(n): dp [1] * n i2 i3 i5 0 for i in range(1, n): next2 dp[i2] * 2 next3 dp[i3] * 3 next5 dp[i5] * 5 dp[i] min(next2, next3, next5) if dp[i] next2: i2 1 if dp[i] next3: i3 1 if dp[i] next5: i5 1 return dp[-1]3.3 关键点解析指针更新逻辑使用三个独立的if语句而非if-else因为可能存在多个指针产生相同最小值的情况如2×36和3×26空间优化虽然使用了O(n)空间存储丑数序列但这是必要的因为我们需要基于前面的丑数计算后面的丑数边界处理n1时直接返回1这是由丑数定义决定的4. 算法优化与变种4.1 使用堆的替代方案除了动态规划我们还可以使用最小堆来解决这个问题。具体步骤初始化堆放入第一个丑数1每次取出堆顶元素x将2x、3x、5x加入堆需去重重复n次第n次取出的就是第n个丑数这种方法的时间复杂度为O(nlogn)空间复杂度O(n)。虽然不如动态规划高效但思路更直观且易于扩展到处理其他类似问题。4.2 超级丑数问题超级丑数是丑数问题的扩展其质因数不限于2、3、5而是由给定的质数列表决定。例如给定质数列表[2,7,13,19]则对应的超级丑数序列为1,2,4,7,8,13,14,16,19,...解决思路与常规丑数问题类似只需将固定的三个指针扩展为与质数列表长度相同的多个指针即可。动态规划解法的时间复杂度为O(nk)其中k是质数列表的长度。5. 实际应用与面试技巧5.1 丑数问题的实际应用虽然丑数问题看似理论性较强但它在以下场景中有实际应用图像处理中的像素值量化音乐理论中的音阶计算金融领域的利率计算模型计算机图形学中的颜色混合算法5.2 面试常见问题与回答技巧在技术面试中面试官可能会提出以下变种问题如何判断一个数是否为丑数解答不断除以2、3、5看最终结果是否为1如果要求第n个只包含质因数2和3的数字如何修改算法解答只需去掉与5相关的指针和计算即可如何证明你的算法是正确的解答数学归纳法每个丑数都是由更小的丑数乘以2、3或5得到5.3 性能优化思考题如何进一步优化空间复杂度提示观察丑数序列的生成规律可能不需要存储所有前序丑数如果n非常大如1e9如何优化提示寻找丑数生成的数学规律或周期性如何并行化计算丑数序列提示考虑丑数序列的生成是否可以分块并行处理6. 常见错误与调试技巧6.1 典型错误案例指针更新不全当多个指针产生相同最小值时只更新了一个指针错误示例使用if-elif而不是多个if语句结果会漏掉某些丑数导致序列错误整数溢出当n较大时丑数可能超出整数范围解决方案使用长整型或检查边界条件初始条件错误忘记将1作为第一个丑数结果整个序列都会错位6.2 调试技巧打印中间结果在循环中打印dp数组和指针位置观察生成过程小规模测试先用n10测试手动验证前10个丑数是否正确边界测试测试n1和n2等特殊情况性能分析使用时间测量工具验证算法的时间复杂度6.3 测试用例设计全面的测试应该包括基础案例n1, n5, n10边界案例n0应特殊处理n1689已知较大丑数性能案例n10000验证算法效率随机案例随机选择n值验证结果正确性7. 扩展学习与资源推荐7.1 相关算法题目Leetcode 263判断数字是否为丑数Leetcode 1201超级丑数变种Leetcode 313超级丑数剑指Offer 49丑数中文版题目7.2 推荐学习资料《算法导论》中的动态规划章节《编程珠玑》中的算法设计技巧Leetcode讨论区的高票解答GeeksforGeeks上的丑数专题7.3 在线练习平台Leetcode原题练习HackerRank的算法挑战Codeforces的比赛题目牛客网的在线编程题库8. 个人实现心得在实际编码过程中我发现以下几点特别值得注意指针更新是算法中最容易出错的部分务必使用多个独立的if语句而非if-else链在面试环境下可以先写出暴力解法再逐步优化到动态规划解法展示思考过程对于Python实现使用列表预分配空间如dp [0]*n比动态扩展更高效当处理极大n值时可以考虑使用生成器来节省内存但会增加时间复杂度一个容易被忽视的优化点是当n超过一定值如1690时可以预先计算并存储结果因为题目通常有n的范围限制。这在竞赛编程中是一个实用技巧。
延伸阅读

更多相关文章

2026/10/14 14:55:08

JavaMail邮件发送实战:从SMTP原理到附件、HTML邮件及常见坑排查

写邮件这个需求,在Java里已经存在十几年了。JavaMail(javax.mail)这套API从JDK早期就是标配,到现在依然是绝大多数邮件发送功能的核心。不管你是要做一个用户注册验证码、订单通知,还是把报表定时发给老板,…

2026/10/14 14:55:08

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

1. 问题定义与数学背景丑数(Ugly Number)是指只包含质因数2、3或5的正整数。LeetCode第264题要求我们找出第n个丑数。这个问题看似简单,但蕴含着深刻的数学原理和算法设计思想。从数学角度看,丑数序列可以看作是由1开始&#xff0…

2026/10/14 14:55:08

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

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

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
免费获取方案
☎咨询二维码 ☎ ↑