直接递归因重复计算导致指数级时间复杂度,记忆化通过查表、计算、存储三步将时间优化至o(n);std::unordered_map比std::map更高效,键需完备覆盖所有参数且查表逻辑不可遗漏。

为什么直接递归会慢得离谱?
因为重复计算。比如 fib(5) 会反复调用 fib(3) 和 fib(2) 多次,子问题规模每减 1,调用次数就指数级膨胀。不加干预的话,fib(40) 就要算上亿次——这不是算法问题,是结构缺陷。
记忆化不是“优化”,而是把递归从 O(2ⁿ) 拉回 O(n) 的必要补丁。
std::map 做记忆表要注意什么?
std::map 看似方便,但每次 operator[] 查找+默认构造+赋值,开销不小;更关键的是,它不保证线程安全,且键比较(比如自定义结构体)容易漏写 operator 或导致逻辑错误。
实操建议:
- 优先用
std::unordered_map,哈希查找平均 O(1),尤其对int、std::pair<int></int>这类可哈希类型 - 如果非用
std::map,确保键类型已正确定义比较逻辑,例如struct Key { int a, b; bool operator - 避免在递归函数内部声明 map —— 每次调用都重建,记忆失效;应作为参数传入或用 static 局部变量(注意多线程风险)
带记忆的斐波那契怎么写才不出错?
核心是「查表→命中则返回→未命中则算、存、返」,三步缺一不可。常见错误是只存不查,或查了但没处理未命中分支。
一个健壮的实现示例(C++17):
long long fib(int n, std::unordered_map<int long>& memo) {
if (n second;
memo[n] = fib(n-1, memo) + fib(n-2, memo);
return memo[n;
}</int>
调用方式:std::unordered_map<int long> memo; fib(40, memo);</int>
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
注意点:
- 不要用
memo[n]直接取值——这会触发默认构造(如long long()),返回 0,掩盖逻辑错误 - 参数用引用传递(
&),否则 map 拷贝开销大,且记忆只在单次调用内有效 - 基础 case(
n )必须放在查表前,否则小输入也进哈希查找,得不偿失
多参数递归怎么套用这个模式?
比如求二维网格路径数:dp(i, j) 表示从 (0,0) 到 (i,j) 的走法数,状态由两个整数决定。
方案一(推荐):用 std::pair<int></int> 作 key,需确认编译器支持其哈希(C++17 起 std::hash<:pair>></:pair> 是标准的):
std::unordered_map<:pair>, int> memo;
// 使用时:memo[{i, j}] = ...</:pair>
方案二:手动编码成单整数,如 i * 10000 + j(需确保 j
切记:所有输入参数都要进 key,漏掉任何一个,就会把不同子问题当成同一个来查——这是最隐蔽也最常发生的 bug。
复杂点不在语法,而在于 key 设计是否完备、查表逻辑是否覆盖所有入口。一旦漏掉某个边界或参数组合,记忆化就变成「伪加速」,结果还可能错。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










