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

LeetCode 70爬楼梯:除了动态规划,C++程序员还能用这几种骚操作解题?

LeetCode 70爬楼梯:C++程序员的五种高阶解法实战

当你第一次在LeetCode上遇到爬楼梯问题时,动态规划可能是最直接的解法。但作为一名追求极致的C++程序员,你是否想过这个问题背后隐藏着更多可能性?让我们跳出思维定式,探索五种截然不同的解法,从时间复杂度O(n)到O(log n),甚至O(1)的极致优化。

1. 动态规划的经典实现与空间优化

动态规划确实是解决爬楼梯问题的标准答案,但即便是这个"标准答案",也有多种实现方式和优化空间。我们先从最基础的版本开始:

int climbStairs(int n) { if (n <= 2) return n; vector<int> dp(n+1); dp[1] = 1; dp[2] = 2; for (int i = 3; i <= n; ++i) { dp[i] = dp[i-1] + dp[i-2]; } return dp[n]; }

这个版本使用了O(n)的空间复杂度,但实际上我们只需要保存前两个状态:

int climbStairs(int n) { if (n <= 2) return n; int prev = 1, curr = 2; for (int i = 3; i <= n; ++i) { int next = prev + curr; prev = curr; curr = next; } return curr; }

提示:在面试中,展示从基础版本到优化版本的思考过程,往往比直接给出最优解更能体现你的问题解决能力。

2. 数学公式法:斐波那契的闭式表达式

爬楼梯问题实际上是斐波那契数列的一个变种。斐波那契数列有一个著名的闭式表达式——比奈公式:

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

在C++中实现这个公式需要注意浮点数精度问题:

#include <cmath> int climbStairs(int n) { const double sqrt5 = sqrt(5); const double phi = (1 + sqrt5) / 2; return round(pow(phi, n + 1) / sqrt5); }

这种方法的时间复杂度是O(1),但要注意:

  • 当n较大时,浮点数运算可能引入精度误差
  • 在实际编程竞赛中,通常会预先计算一定范围内的结果

3. 矩阵快速幂:算法竞赛中的高级技巧

对于追求极致性能的场景,矩阵快速幂可以将时间复杂度降到O(log n)。这个方法的理论基础是斐波那契数列的矩阵表示:

[ F(n) ] = [1 1]^(n-1) [F(1)] [ F(n-1) ] [1 0] [F(0)]

C++实现如下:

#include <vector> using namespace std; vector<vector<long long>> multiply(vector<vector<long long>>& a, vector<vector<long long>>& b) { vector<vector<long long>> res(2, vector<long long>(2)); res[0][0] = a[0][0]*b[0][0] + a[0][1]*b[1][0]; res[0][1] = a[0][0]*b[0][1] + a[0][1]*b[1][1]; res[1][0] = a[1][0]*b[0][0] + a[1][1]*b[1][0]; res[1][1] = a[1][0]*b[0][1] + a[1][1]*b[1][1]; return res; } vector<vector<long long>> matrixPow(vector<vector<long long>>& a, int n) { vector<vector<long long>> res = {{1,0},{0,1}}; // 单位矩阵 while (n > 0) { if (n & 1) res = multiply(res, a); a = multiply(a, a); n >>= 1; } return res; } int climbStairs(int n) { if (n <= 2) return n; vector<vector<long long>> mat = {{1,1},{1,0}}; auto res = matrixPow(mat, n-1); return res[0][0] + res[0][1]; }

4. 递归与记忆化:理解问题本质

虽然纯递归解法在时间复杂度上不占优势(O(2^n)),但通过记忆化可以将其优化到O(n):

#include <unordered_map> unordered_map<int, int> memo; int climbStairs(int n) { if (n <= 2) return n; if (memo.find(n) != memo.end()) return memo[n]; memo[n] = climbStairs(n-1) + climbStairs(n-2); return memo[n]; }

这种方法虽然不如迭代版本的动态规划高效,但在某些需要自顶向下思考的问题中更为直观。

5. 不同解法的性能实测对比

为了真正理解各种解法的优劣,我在LeetCode测试平台上进行了实测比较(n=45):

方法时间复杂度空间复杂度实际运行时间(ms)
基础DPO(n)O(n)0
优化DPO(n)O(1)0
数学公式O(1)O(1)0
矩阵快速幂O(log n)O(1)0
递归+记忆化O(n)O(n)0
纯递归O(2^n)O(n)超时

有趣的是,对于n=45这样相对较小的输入,各种优化解法在实际运行时间上差异不大。但当n变得非常大时(比如1e18),数学公式法和矩阵快速幂的优势就会显现出来。

http://www.cnnetsun.cn/news/2194320.html

相关文章:

  • ESP固件烧录终极指南:5分钟快速掌握esptool完整用法
  • 如何通过 TaoToken CLI 一键安装包并配置多模型环境
  • 在模型广场中根据任务需求与预算筛选合适大模型的实用思路
  • SNOW-V算法C语言实现
  • 当ChatGPT遇上主动学习:用大模型‘智能提问’,让小模型‘精准成长’
  • 学Simulink——基于Simulink的功能安全(ISO 26262)故障注入与验证​
  • AI工具集合项目解析:从筛选到实践的全流程指南
  • 猫抓浏览器资源嗅探扩展:专业级网页媒体下载解决方案
  • 基于Raycast与OpenAI的智能翻译插件开发实战
  • 基于MongoDB与MCP协议构建AI智能体持久化记忆层
  • 别再只抓包了!手把手教你用OpenSSL验证‘挑战-响应’身份鉴别的签名(附完整数据包分析)
  • Python大模型微调不是调参,是系统工程:我们实测了12种量化+微调组合,最终锁定BF16+NF4+GA=2的最优性价比方案
  • 从逆波兰表达式到自制脚本引擎:用C++实现eval()的踩坑与优化实录
  • 终极GlosSI使用指南:让Steam控制器在任何游戏中都能工作
  • 文档重排技术演进与jina-reranker-v3架构解析
  • 别再只测电压了!手把手教你用LTC2944库仑计给锂电池做精准电量监控(附完整Arduino代码)
  • 开箱即用的Docker开发环境:lean-ctx镜像深度解析与实战指南
  • 电感Q值详解:影响谐振电路性能的关键因素
  • 5个简单步骤掌握GlosSI:解锁全平台游戏控制器配置终极指南
  • 5步构建RE引擎游戏Mod:从零开始掌握REFramework开发
  • Appium MCP Server:用自然语言驱动移动端自动化测试
  • 从医学影像到AI模型:我是如何用LIDC-IDRI数据集构建肺癌分类项目第一阶段的
  • taotoken为独立开发者提供稳定可靠的大模型api服务
  • 终极风扇控制方案:FanControl让Windows散热管理如此简单
  • 从数学证明到数据可视化:用Manim CE 0.7制作‘会讲故事’的技术视频
  • CentOS7服务器运维:用yum源管理多版本Golang(稳定版与RC版)实战
  • YimMenu终极指南:如何打造GTA5最强防护与游戏增强体验
  • 从《原神》模型到Unity特效:手把手教你拆解‘消融为灰’的两种ShaderGraph实现方案
  • 高压均质机HPH构造详解:三大核心模块
  • 【FreeRTOS+STM32 C语言深度优化】:仅改11行关键代码,系统吞吐量翻倍、栈溢出归零的工业级方案