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

小明的魔法地图:迷宫探险智慧(记忆性递归)

🌲 故事:小明的迷宫探险与“魔法地图”

🌍 背景:神秘的数字迷宫

小明来到一座古老的迷宫。迷宫有 n 个房间,从房间 0 开始,每次可以:

  • 走到房间 n-1(走1步)

  • 或直接跳到房间 n-2(走2步)

他的任务是:从房间 n 走到房间 0,有多少种不同的路径?

这其实就是 爬楼梯问题,但我们现在把它想象成一个图上的搜索问题


🧭 第一章:深度优先搜索(DFS)—— 小明的盲目探索

小明决定用 深度优先搜索(DFS) 来探索所有路径。

他从房间 5 出发,开始“递”:

f(5)├── f(4)│   ├── f(3)│   │   ├── f(2)│   │   │   ├── f(1) → f(0) ✅(一条路径)│   │   │   └── f(0) ✅│   │   └── f(1) → f(0) ✅│   └── f(2) → 同上 ✅└── f(3) → 又从头算一遍!😱

👉 他发现:f(3) 被算了 两次f(2) 被算了 三次……

他累得满头大汗:“这迷宫太深了,我一直在走重复的路!”

❌ 问题:纯 DFS 会重复探索相同的子问题,效率极低,时间复杂度 O(2^n)。


🗺 第二章:魔法地图登场 —— 记忆化递归

一位智者出现,递给小明一张 “魔法地图”memo):

“孩子,每次你探索完一个房间,就把从那里到终点的路径总数记在地图上。下次再来,就不用再探了。”

小明恍然大悟!

🧩 魔法地图规则(记忆化递归)

class Solution {private:unordered_map<int, int> memo;  // 魔法地图:记录 f(n) = 从房间 n 到 0 的路径数​public:int dfs(int n) {// 🔍 第一步:进入房间 n,先看地图!if (memo.find(n) != memo.end()) {return memo[n];  // ✅ 地图有记录,直接返回!不再“递”下去!}​// 🧱 基础情况:房间 1 和 2if (n == 1) return 1;if (n == 2) return 2;​// 🚶•♂️ 第一次来:开始“递”——深入探索 f(n-1) 和 f(n-2)int ways = dfs(n - 1) + dfs(n - 2);​// 📝 探索结束,在“归”的路上,把结果记入地图memo[n] = ways;​// 🏁 返回结果return ways;}​int climbStairs(int n) {return dfs(n);}};

🎬 第三章:魔法地图如何工作?—— “递” vs “归”

我们以 f(5) 为例,看看魔法地图何时“记录”,何时“优化”。

🌦 第一次探索 f(5):建立地图

f(5)├── f(4)│   ├── f(3)│   │   ├── f(2) → 2│   │   └── f(1) → 1│   │   → f(3) = 3,归时记入 memo[3]=3 ✅(归:记录)│   └── f(2) → 2│   → f(4)=5,归时记入 memo[4]=5 ✅(归:记录)└── f(3) → 还没记完,继续

👉 在“”的过程中,小明把 f(3)f(4) 的结果写入了魔法地图。


☀️ 第二次遇到 f(3):触发优化!

f(5) 要调用 f(3) 时:

 if (memo.find(3) != memo.end()) return memo[3];  // ✅ 查表成功!
  • 这个判断发生在 “递”的最开始

  • 小明甚至不用走进房间 3,直接说:“我知道,有 3 种走法!”

  • 整个 f(3) 子树被跳过!

优化发生在这里:在“递”的过程中,查表成功,跳过递归!


🌟 关键结论:优化到底在“递”还是“归”?

阶段发生了什么是否优化?
第一次 f(3) 的“归”f(3)=3 写入 memo❌ 准备工作(无优化)
第二次 f(3) 的“递”查表成功,直接返回优化真正发生!

📌 所以:

  • “归”是播种:把结果记下来,为未来优化做准备。

  • “递”是收获:在后续的“递”中,利用记忆避免重复探索。

  • 优化的本质效果,发生在“递”的过程中。


🧠 深度优先搜索(DFS)与记忆化的关系

概念对应故事中的角色
DFS(深度优先搜索)小明一条路走到黑,深入迷宫
递归小明不断进入新房间,靠“记忆”返回
函数调用栈小明的“记忆栈”:记得自己是从哪个房间来的
记忆化(memo)魔法地图:记录已探索房间的结果
优化时机在“递”时查地图,避免重复进入

记忆化递归 = DFS + 记忆表 它让 DFS 从“盲目探索”变成“聪明搜索”。


📊 效果对比

n纯 DFS(递归)调用次数记忆化 DFS 调用次数
515 次9 次
10~200 次19 次
40~1万亿次 ❌79 次 ✅

小明从“累死也走不完”变成了“秒答如流”。


✅ 总结:记忆化递归的三大智慧

  1. “递时查表”:每次进入函数,先查 memo,避免重复递归。

  2. “归时记录”:计算完结果后,在返回前存入 memo

  3. “用空间换时间”:多用一点内存(memo),换来指数级的速度提升。


🚀 最终代码(带故事注释)

 class Solution {private:unordered_map<int, int> memo;  // 🗺 魔法地图:记录每个房间到终点的路径数​public:int dfs(int n) {// 🔍 【优化发生在这里!】// 进入房间 n,先看地图:如果已经探索过,直接返回答案if (memo.find(n) != memo.end()) {return memo[n];  // ✅ 跳过整个子树,不再“递”下去}​// 🧱 基础情况:房间 1 和 2if (n == 1) return 1;if (n == 2) return 2;​// 🚶•♂️ 第一次来:开始“递”——深入探索子房间int ways = dfs(n - 1) + dfs(n - 2);​// 📝 【归时记录】探索结束,在返回前把结果记入地图memo[n] = ways;​// 🏁 返回结果return ways;}​int climbStairs(int n) {return dfs(n);}};

🌈 故事的启示

递归是深度优先搜索的实现方式,而记忆化是给 DFS 装上“记忆”和“智慧”。

小明学会了:

  • 归时记一笔,递时省一步

  • 不走重复路,才是真高手

你也已经掌握了这门“魔法”,恭喜!🧙‍♂️✨


如果你还想看“回溯”、“动态规划”等更多故事版本,我也可以继续讲下去 😊

http://www.xdnf.cn/news/1275913.html

相关文章:

  • 【0基础3ds Max】主工具栏介绍(下)
  • [激光原理与应用-223]:机械 - 机加厂加工机械需要2D还是3D图?
  • Python设计模式 - 装饰模式
  • 六、RuoYi-Cloud-Plus OSS文件上传配置
  • QT常用控件三
  • Qt—— 下载、工具介绍以及新建项目
  • 从0开始的中后台管理系统-5(userList页面功能实现)
  • 40.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--扩展功能--集成网关--初始化网关
  • Pytorch进阶-timm库-00快速开始
  • (三)全栈(部署)
  • 精准计算Word文档页数的PHP类
  • 数据结构-deque(双端队列)和queue(队列)区别
  • 【npm、yarn、pnpm】特点对比,按需选择
  • Java 后端性能优化实战:从 SQL 到 JVM 调优
  • 分布微服务电商订单系统Rust编码开发[上]
  • 数组练习(一)
  • vuhub drippingblues靶场攻略
  • #4:MinIO分片上传和集群部署
  • 攻击实验(ARP欺骗、MAC洪范、TCP SYN Flood攻击、DHCP欺骗、DHCP饿死)
  • 安全运维的核心
  • C语言——深入理解指针(二)
  • 【递归、搜索与回溯算法】递归算法
  • Ollama+Deepseek+Docker+RAGFlow打造自己的私人AI知识库
  • 计算机网络:超网即路由聚合一定需要连续的IP地址吗?
  • 秋招春招实习百度笔试百度管培生笔试题库百度非技术岗笔试|笔试解析和攻略|题库分享
  • RabbitMQ面试精讲 Day 19:网络调优与连接池管理
  • Spring Boot 注解详解:@RequestMapping 的多种用法
  • 十、Linux Shell脚本:流程控制语句
  • Day41--动态规划--121. 买卖股票的最佳时机,122. 买卖股票的最佳时机 II,123. 买卖股票的最佳时机 III
  • 网闸技术解析:如何实现对国产数据库(达梦/金仓)的深度支持