一、什么是“递归”
递归,顾名思义,包括“递”和“归”两个过程,“递”的过程就是将原问题一层一层分解下去直到找到终止条件,“归”的过程就是从终止条件开始一层一层向上回归直到归并到原问题。
可以看出,递归需要满足三个条件:
- 原问题能够分解为若干个子问题;
- 子问题与原问题求解思路相同,只是数据规模不同;
- 存在终止条件;
一个经典的递归问题是:
假如这里有 n 个台阶,每次你可以跨 1 个台阶或者 2 个台阶,请问走这 n 个台阶有多少种走法?
求解该问题,可按照递归三个条件来进行:
- 原问题可以分解为两个子问题:下一步走一个台阶、下一步走两个台阶;
- 子问题与原问题求解思路相同,只是数据规模不同:;
- 存在终止条件:;
二、Python使用递归实现走台阶
基于上述原理,可以轻松实现一个递归代码:
def walk_steps(n:int)->int:
if n == 1:
return 1
elif n == 2:
return 2
return walk_steps(n-1) + walk_steps(n-2)
print(walk_steps(7))
三、递归转循环
递归编程思想简单,几行代码即可实现一个人脑思考不过来的递归问题,但却有着致命缺点:堆栈溢出、空间复杂度高!
在编程语言进行函数调用时,采用栈来存放临时变量,因此对于递归函数,其子问题的返回值都会临时存放在栈中,当数据规模变大时,其空间复杂度将极大地提高,容易造成堆栈溢出,函数求解将变得极其困难。
对于上述实现的递归代码,在小数据量时,感觉不到困难,但当数据规模(即总的台阶数n)变大时(大概超过40时)求解将变得极其缓慢,且继续增大到一定规模,就会报堆栈溢出的错误:
RecursionError: maximum recursion depth exceeded in comparison
因此,对于某些递归函数,如果可以转化为非递归,则能大大降低其空间复杂度,同时避免堆栈溢出。下面使用循环方式实现阶梯走法计算:
def walk_steps_circle(n:int)->int:
if n == 1:
return 1
elif n == 2:
return 2
step1 = 1
step2 = 2
step_total = 0
for i in range(3,n+1):
step_total = step1 + step2
step1 = step2
step2 = step_total
return step_total
walk_steps_circle(7)
大家可以在自己机器上试一下,分别给两个函数传入一个较大的参数,看看运行结果,即可发现其明显的差别。