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

从斐波那契到爬楼梯:用Python动态规划解决经典问题,附LeetCode 70题保姆级解析

从斐波那契到爬楼梯:用Python动态规划解决经典问题,附LeetCode 70题保姆级解析

每次看到LeetCode上那些标着"简单"却让人抓耳挠腮的题目,总让我想起自己初学算法时的窘迫。特别是第70题"爬楼梯",表面看是个小学数学题,实则暗藏玄机。今天我们就来拆解这个经典问题,看看它如何与斐波那契数列产生奇妙关联,以及如何用动态规划优雅解决。

1. 问题本质与数学建模

站在楼梯前的小明可能不知道,他面临的其实是个历史悠久的数学问题。当台阶数n=10时,走法总数恰好是斐波那契数列的第11项(如果从F(0)=1开始计数)。这种巧合背后是相同的递推关系:

F(n) = F(n-1) + F(n-2)

为什么这个公式成立?想象你站在第n级台阶上,上一步只能来自:

  • 从n-1级跨1步
  • 从n-2级跨2步

这两种选择互斥且完备,因此总方法数就是两者之和。这就是重叠子问题特性——每个台阶的解都依赖于更小台阶的解。

边界条件需要特别注意:

  • n=1时只有1种走法([1])
  • n=2时有2种走法([1,1]和[2])

用表格表示前几项的关系:

台阶数n12345
走法数F(n)12358

2. 从递归到动态规划的进化

新手最容易想到的递归解法虽然直观,但存在严重性能问题:

def climb_stairs(n): if n == 1: return 1 if n == 2: return 2 return climb_stairs(n-1) + climb_stairs(n-2)

这个解法的时间复杂度是O(2^n),因为每次调用都会分裂成两个子调用。当n=40时,计算量已经超过万亿次。

动态规划通过存储中间结果来优化:

def climb_stairs(n): if n <= 2: return n dp = [0]*(n+1) dp[1], dp[2] = 1, 2 for i in range(3, n+1): dp[i] = dp[i-1] + dp[i-2] return dp[n]

此时时间复杂度降为O(n),空间复杂度也是O(n)。但观察状态转移可以发现,我们只需要保存前两个状态:

def climb_stairs(n): if n <= 2: return n a, b = 1, 2 for _ in range(3, n+1): a, b = b, a+b return b

这种优化将空间复杂度降至O(1),是面试官最期待的写法。

3. 复杂度分析与数学解法

除了动态规划,这个问题还有几种有趣的解法:

矩阵快速幂(时间复杂度O(log n)): 利用斐波那契的矩阵表示,通过快速幂算法加速计算:

def matrix_pow(mat, power): result = [[1,0],[0,1]] while power > 0: if power % 2 == 1: result = matrix_mult(result, mat) mat = matrix_mult(mat, mat) power //= 2 return result def climb_stairs(n): if n <= 2: return n mat = [[1,1],[1,0]] return matrix_pow(mat, n)[0][0]

通项公式法(时间复杂度O(1)): 斐波那契数列有精确的闭式解:

F(n) = (φ^n - ψ^n)/√5 其中φ=(1+√5)/2≈1.618, ψ=(1-√5)/2≈-0.618

Python实现:

import math def climb_stairs(n): sqrt5 = math.sqrt(5) phi = (1 + sqrt5) / 2 return int((phi**(n+1) - (-phi)**(-n-1))/sqrt5)

注意:浮点数精度限制使得这种方法在n>70时可能产生误差

4. 变种问题与实际应用

掌握了基础解法后,可以尝试这些常见变种:

1. 步长变化:如果还能一次跨3步,递推式变为F(n)=F(n-1)+F(n-2)+F(n-3)

def climb_stairs(n): if n <= 2: return n if n == 3: return 4 a, b, c = 1, 2, 4 for _ in range(4, n+1): a, b, c = b, c, a+b+c return c

2. 成本最小化:每个台阶有体力成本,求最小成本路径

def min_cost_climbing(costs): n = len(costs) dp = [0]*n dp[0], dp[1] = costs[0], costs[1] for i in range(2, n): dp[i] = min(dp[i-1], dp[i-2]) + costs[i] return min(dp[-1], dp[-2])

3. 空间约束:在O(1)空间下处理大规模n值(使用生成器):

def fib_gen(): a, b = 0, 1 while True: yield a a, b = b, a+b

这些变种在电商优惠券组合、机器人路径规划等领域都有实际应用。比如优惠券满减问题,就可以建模为"用给定面额的券组合出目标金额的方法数"。

5. 调试技巧与常见错误

在实现动态规划时,这些陷阱需要注意:

  1. 边界条件错误:忘记处理n=0或n=1的情况
  2. 索引偏移:Python列表从0开始,与问题描述的从1开始容易混淆
  3. 空间优化遗漏:没有发现只需要前两个状态的规律
  4. 整数溢出:当n很大时,结果可能超过普通整数范围

调试时可以:

  • 打印dp表格检查中间结果
  • 用小规模测试用例手动验证
  • 比较递归和迭代版本的结果
# 调试示例 def test(): for n in range(1, 10): recursive = climb_stairs_recursive(n) dp = climb_stairs_dp(n) assert recursive == dp, f"Failed at n={n}" print("All tests passed!")

6. LeetCode实战与优化

针对LeetCode 70题,提交时要注意:

  1. 预处理前几个结果加速
  2. 使用位运算代替模运算
  3. 循环展开减少迭代次数

优化后的终极版本:

def climb_stairs(n): if n <= 3: return n a, b = 2, 3 for _ in range(4, n+1): a, b = b, a + b return b

对于特别大的n(比如1e18),需要使用快速幂算法或者找规律发现周期性。我在一次周赛中遇到过n上限为1e100的变种题,最终通过观察斐波那契数列模某个数的周期性解决了问题。

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

相关文章:

  • YOLOv8-nano+onnxruntime-web避坑实录:我的第一个浏览器端AI项目
  • VScode高效清理代码:正则表达式一键删除指定行与空白行
  • waitpid
  • 前辈学习C语言的四种方法,实际上不管学什么语言,都行之有效
  • Python自动化操作Creo的5个实用技巧(附代码示例)
  • StructBERT中文情感分类:SpringBoot微服务集成指南
  • 大数据开发场景中,Python 常用且易错易混淆的知识点总结(附:从实战角度梳理的 Python 知识体系)
  • React Fiber 渲染机制详解
  • Agent 开发框架(三)LangGraph
  • 【优化调度】基于matlab遗传算法GA大规模人工智能模型训练任务调度【含Matlab源码 15344期】
  • 别再只用WSL1了!Win10 2004版保姆级升级WSL2教程(含性能对比与文件系统避坑指南)
  • 基于NDT算法的双VLP-16激光雷达外参标定实战:从单机启动到多机协同
  • 5G NR物理层设计精要:为什么子载波间隔能灵活可变?它对时延和覆盖有何影响?
  • PlantDoc数据集升级:从开源标注到精准农业对象检测的实践
  • Python 中主要数据类型分类及特性总结(附:可哈希 (Hashable) 与 不可哈希 (Unhashable) 详解)
  • SQL处理大规模分组聚合的内存限制_调整服务器配置
  • DPABI/DPARSF新手避坑指南:从DICOM到NIFTI,我的预处理血泪史
  • 《算法竞赛中的初等数论》精讲:从零到精通的十五万字实战指南
  • OpenClaw 低代码部署教程 小白也能快速上手
  • 基于LightGBM与多因子指标的股票涨跌预测实战
  • 游戏引擎‘潜规则’:为什么你的法线贴图在Unity里凸,到UE4里就凹了?
  • 【UE5】Groom毛发系统进阶指南——从3DsMax到UE的毛发材质与物理模拟全流程
  • 2026年质量好的PETG包装管/PS包装管横向对比厂家推荐 - 品牌宣传支持者
  • SerialPlot终极指南:5个技巧掌握实时串口数据可视化
  • Go语言怎么做链路追踪_Go语言分布式链路追踪教程【精选】.txt
  • 互联网大厂 Java 求职面试:从音视频场景到微服务技术的探讨
  • PY烧录器从入门到量产:手把手教你批量烧录PY32F002B(附UID加密实战)
  • PCIe硬件电路设计实战:从理论到PCB布局的关键要点
  • LeetCode 3761. 镜像对之间最小绝对距离 (多算法优化版)
  • 塑料件用润滑脂有什么讲究