递归
递归一直是搞不明白,而且越往里想越糊涂,这里借鉴别人的想法结合自己的理解,并结合力扣题目深入理解递归。
递归是在函数中存在调用自身的现象
1 | 假设我们用递归来算阶乘 f(n) |
1 | 例如计算f(4) |
递归过程就是逐步展开递推然后在回归计算的过程
递归代码最重要的两个特征:结束条件和自我调用。自我调用是在解决子问题,而结束条件定义了最简子问题的答案。
递归思维
在知乎上对递归的讨论中,有两个回答我觉得非常的形象
递归思维就是摊派任务
假设你是老板,你就把活分给各个分管副总,各个副总再把活分给自己下一级的各个部门总监,
总监再把活分给下面各个干活的经理,最后分到最基层干活的人手上,
然后等待下面的完成结果再反向一级级的向上汇报。
等你当了老板就没这个疑问了,
这里面难在事情该怎么分才是合理的,怎么保证下一级都能及时的给出结果,从而快速有效的完成总任务。
递归可以想象成查字典
你遇到一个【生词 1】,然后去查字典。
发现这个【生词 1】的解释里又碰见一个【生词 2】,接着你又去查这个【生词 2】的意思,
没想到【生词 2】里又遇到一个【生词 3】…
于是只有当你查完【最后一个】【生词 N】的时候,
你才可以依次理解【生词 N-1】,【生词 N-2】…【生词 2】【生词 1】。
斐波那契数(力扣509)
题目:
斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给你 n ,请计算 F(n) 。示例 1:
输入:2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1
示例 2:输入:3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2
示例 3:输入:4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3
分析
斐波那契数是入门递归的第一步,可以画出递归树如下图所示:
求f(5)需要知道f(4)和f(3),直到f(1)和f(2),结果已知,可直接返回。
1 | class Solution: |
我们发现在计算f(4)时算了f(3),计算f(5)时也重复算了f(3),对计算资源消耗较大,我们可以使用备忘录,用空间换时间,计算完f(3)后,以后的f(3)都是用查表操作。表可以使用字典或者数组都行,代码如下:
1 | # 使用数组做备忘录 |
1 | #使用字典做备忘录 |
这是从上到下的使用递归的解法,也可从下到上,使用迭代。
1 | class Solution: |
第 N 个泰波那契数(力扣1137)
题目
泰波那契序列 Tn 定义如下:
T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2
给你整数 n,请返回第 n 个泰波那契数 Tn 的值。
示例 1:
输入:n = 4
输出:4
解释:
T_3 = 0 + 1 + 1 = 2
T_4 = 1 + 1 + 2 = 4
示例 2:输入:n = 25
输出:1389537
分析
首先使用递归解法:
1 | class Solution: |
同样使用带备忘录的递归
1 | class Solution: |
使用迭代的方法:
和上题思路一样,只不过变成了3数相加,循环也应该少循环一次(循环几次可以带n=3进去预演一下,本题n=3时只需循环一次,n=4需循环2次,故而range(n-2))
1 | class Solution: |