一、什么是“递归”

递归,顾名思义,包括“递”和“归”两个过程,“递”的过程就是将原问题一层一层分解下去直到找到终止条件,“归”的过程就是从终止条件开始一层一层向上回归直到归并到原问题。

可以看出,递归需要满足三个条件:

  • 原问题能够分解为若干个子问题;
  • 子问题与原问题求解思路相同,只是数据规模不同;
  • 存在终止条件;

一个经典的递归问题是:

假如这里有 n 个台阶,每次你可以跨 1 个台阶或者 2 个台阶,请问走这 n 个台阶有多少种走法?

求解该问题,可按照递归三个条件来进行:

  1. 原问题可以分解为两个子问题:下一步走一个台阶、下一步走两个台阶;
  2. 子问题与原问题求解思路相同,只是数据规模不同:;
  3. 存在终止条件:;

二、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)

大家可以在自己机器上试一下,分别给两个函数传入一个较大的参数,看看运行结果,即可发现其明显的差别。