从爬楼梯到算斐波那契,我终于弄懂了递归和动态规划这俩 "磨人精"

最近在代码界摸爬滚打,总被两个词按在地上摩擦 ------ 递归和动态规划。这俩货就像数学题里的 "小明",天天换着花样折磨人,今天就来好好扒一扒它们的底裤。

递归:自己调自己的 "套娃大师"

递归这东西,说白了就是函数自己喊自己的名字。就像小时候问妈妈 "我从哪来的",妈妈说 "你是妈妈生的",再问 "妈妈从哪来的",妈妈说 "外婆生的"... 一直问到祖宗十八代,这就是递归的精髓 ------ 找规律 + 找出口

比如算个阶乘,用递归(时间复杂度过高)写出来是这样:

js 复制代码
function mul(n){

   if(n === 1){ // 出口:问到祖宗了

       return 1

   }

   return n * mul(n-1) 

}

这代码简洁得像诗,但算个斐波那契数列就露馅了。那个 1,1,2,3,5,8... 的数列,递归写法看着简单:

递归的 "中年危机":重复计算让 CPU 原地冒烟

js 复制代码
function fb(n){

   if(n === 1 || n === 2){

       return 1

   }

   return fb(n-1) + fb(n-2)

}

这代码算个 n=10 还行,要是算 n=40,能让你喝杯咖啡回来还没出结果。就像你查快递单号,每次都要从快递员刚取件的时候查起,哪怕昨天刚查过。

给递归装个 "备忘录":记忆化搜索救场

比如爬楼梯问题:一次能爬 1 或 2 阶,到第 n 阶有几种走法?

后来我灵机一动,给递归加了个小本本(数组 f):

js 复制代码
const f = []
var climbStairs = function (n) {
    if (n === 1 || n === 2) {
        return n
    }
    if (f[n] === undefined) { // 查小本本,没记过才计算
        f[n] = climbStairs(n - 1) + climbStairs(n - 2)
    }
    return f[n]
};

这招叫 "记忆化搜索"(提效),相当于把算过的结果记在通讯录里,下次直接拨号不用重新查号。

后来才发现,这代码就像给老年机装了智能手机的通讯录 ------ 思路对但效率不够。全局数组 f 在多组测试用例下会残留历史数据,而且递归调用本身就有函数栈的开销,n 太大时还是扛不住。

彻底换个活法:动态规划的 "自底向上" 哲学

  • 站在已知的角度,通过已知来定位未知 最后改用纯动态规划找到动态方程)写法,直接逆袭:
js 复制代码
var climbStairs = function (n){
    const f = []
    // 先搞定已知的1楼和2楼
    f[1] = 1
    f[2] = 2
    // 从3楼开始往上爬,每步都踩在前人的肩膀上
    for(let i = 3;i<=n;i++){
        f[i] = f[i-1] + f[i-2]
    }
    return f[n]
 }

这思路就像盖楼,从 1 层开始一层层往上盖,每一层的建材都直接用前两层的,根本不用回头看。没有递归的函数调用开销,也没有重复计算,效率直接拉满。

总结:三种写法的生存现状

写法 特点 适合场景
纯递归 代码简洁如诗 理解思路用,n≤30
记忆化搜索 加了缓存的递归 教学演示,n≤1000
动态规划 自底向上迭代 实际开发,n多大都不怕

总结:什么时候该套娃,什么时候该记笔记?

  • 递归适合简单问题或调试时用,写起来爽,但容易重复劳动

  • 动态规划适合复杂问题,虽然前期要多写几行,但跑起来飞快

  • 记住:所有动态规划问题,先建个空数组当小本本准没错

现在终于明白,递归是浪漫的诗人,只顾优雅不管效率; 动态规划是务实的会计,每一笔账都记得清清楚楚。 下次再遇到这俩货,我可不会再被它们忽悠了!

相关推荐
2501_901147834 分钟前
PyTorch DDP官方文档学习笔记(核心干货版)
pytorch·笔记·学习·算法·面试
Serene_Dream5 分钟前
Java 垃圾收集器
java·jvm·面试·gc
刘联其10 分钟前
.net也可以用Electron开发跨平台的桌面程序了
前端·javascript·electron
韩曙亮10 分钟前
【jQuery】jQuery 选择器 ④ ( jQuery 筛选方法 | 方法分类场景 - 向下找后代、向上找祖先、同级找兄弟、范围限定查找 )
前端·javascript·jquery·jquery筛选方法
前端 贾公子10 分钟前
Node.js 如何处理 ES6 模块
前端·node.js·es6
pas13616 分钟前
42-mini-vue 实现 transform 功能
前端·javascript·vue.js
你的代码我的心43 分钟前
微信开发者工具开发网页,不支持tailwindcss v4怎么办?
开发语言·javascript·ecmascript
esmap43 分钟前
OpenClaw与ESMAP AOA定位系统融合技术分析
前端·人工智能·计算机视觉·3d·ai·js
毕设源码-钟学长1 小时前
【开题答辩全过程】以 基于node.js vue的点餐系统的设计与实现为例,包含答辩的问题和答案
前端·vue.js·node.js
努力d小白1 小时前
leetcode438.找到字符串中所有字母异位词
java·javascript·算法