◼ 递归:函数(方法)直接或间接调用自身。是一种常用的编程技巧
◼ 如果递归调用没有终止,将会一直消耗栈空间
最终导致栈内存溢出(Stack Overflow)
◼ 所以必需要有一个明确的结束递归的条件
也叫作边界条件、递归基
1.递归的基本思想
◼ 拆解问题
把规模大的问题变成规模较小的同类型问题
规模较小的问题又不断变成规模更小的问题
规模小到一定程度可以直接得出它的解 n n – 1 n – 2 .... 2 1
◼ 求解
由最小规模问题的解得出较大规模问题的解
由较大规模问题的解不断得出规模更大问题的解
最后得出原来问题的解
◼ 凡是可以利用上述思想解决问题的,都可以尝试使用递归
很多链表、二叉树相关的问题都可以使用递归来解决
✓ 因为链表、二叉树本身就是递归的结构(链表中包含链表,二叉树中包含二叉树)
2.递归的使用套路
① 明确函数的功能
先不要去思考里面代码怎么写,首先搞清楚这个函数的干嘛用的,能完成什么功能?
② 明确原问题与子问题的关系
寻找 f(n) 与 f(n – 1) 的关系
③ 明确递归基(边界条件)
递归的过程中,子问题的规模在不断减小,当小到一定程度时可以直接得出它的解
寻找递归基,相当于是思考:问题规模小到什么程度可以直接得出解?
3.相关练习
1.练习1 – 斐波那契数列(详细优化查看学习资料)
◼ 斐波那契数列:1、1、2、3、5、8、13、21、34、……
F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n≥3)
◼ 编写一个函数求第 n 项斐波那契数
◼ 根据递推式 T n = T n − 1 + T(n − 2) + O(1),可得知时间复杂度:O(2^n)
◼ 空间复杂度:O(n)
递归调用的空间复杂度 = 递归深度 * 每次调用所需的辅助空间
2.练习2 – 上楼梯(跳台阶)
◼ 楼梯有 n 阶台阶,上楼可以一步上 1 阶,也可以一步上 2 阶,走完 n 阶台阶共有多少种不同的走法?
假设 n 阶台阶有 f(n) 种走法,第 1 步有 2 种走法
✓ 如果上 1 阶,那就还剩 n – 1 阶,共 f(n – 1) 种走法
✓ 如果上 2 阶,那就还剩 n – 2 阶,共 f(n – 2) 种走法
所以 f(n) = f(n – 1) + f(n – 2)
70. 爬楼梯
3.练习3 – 汉诺塔(Hanoi)(详细题解查看学习资料)
◼ 编程实现把 A 的 n 个盘子移动到 C(盘子编号是 [1, n] )
每次只能移动1个盘子
大盘子只能放在小盘子下面
◼ 其实分 2 种情况讨论即可
当 n == 1时,直接将盘子从 A 移动到 C
当 n > 1时,可以拆分成 3大步骤
① 将 n – 1 个盘子从 A 移动到 B
② 将编号为 n 的盘子从 A 移动到 C
③ 将 n – 1 个盘子从 B 移动到 C
✓ 步骤 ① ③ 明显是个递归调用
递归转非递归的详细方法查看学习资料