递归

1 什么是递归

  1. 递归是一种非常高效,简洁的编码技巧,一种应用非常广泛的算法。比如 DFS 深度优先搜索、前后中序二叉树遍历等都是使用递归。
  2. 方式或函数调用自身的方式,称之为递,返回称之为归。
  3. 基本上,所有的递归问题都可以用递归公式来表示,例如:
    f(n) = f(n-1) +1;
    f(n) = f(n-1) + f(n+2)
    f(n) = n * f(n-1);

为什么使用递归?

  1. 好处:代码表达力强,简洁。
  2. 坏处:空间复杂度高,有堆栈溢出风险,存在重复计算,过多的函数调用会耗时较多。

什么样的问题可以用递归解决?

如果一个问题同时满足以下 3 个条件,就可以用递归来解决:

  1. 问题的解可以分解成几个子问题的解,何为子问题?就是数据规模更小的问题。
  2. 问题和子问题,除了数据规模不同,求解思路完全相同。
  3. 存在递归终止条件。

如何实现递归

  1. 递归代码编写
    • 写递归代码的关键在于,如果找到将大问题分解成子 问题的规律,并且基于此写出递推公式,然后再推敲终止条件,最后将递归公式和终止条件翻译成代码。
  2. 递归代码理解
  • 对于递归代码,若试图搞清楚整个递和归的过程,实际上是进入了思维误区。
  • 那改如何理解递归代码呢?
    • 如果一个 A 问题可以分解成 B,C,D 子问题,那你可以假设子问题 B,C,D 已经被解决,而且,你只需要思考问题 A 和问题 BCD 两层之间的关系即可。不需要一层层往下思考子问题和子子问题,子子问题与子子子问题之间的关系。屏蔽掉递归细节,这样理解起来就简单多了。
    • 因此,理解递归代码,就把他抽象成一个递归公式,不要想象成一层层的调用关系,不要试图用人脑去分解递归的每个步骤。

递归常见问题及解决方案

  1. 警惕堆栈溢出:可以使用一个全局计数器控制堆栈的深度。
  2. 警惕重复计算:可以使用 Set 结构保存已经解开过的值,避免重复计算。

如何将递归代码改成非递归代码?

笼统的讲,所有的递归代码都可以改写成迭代循环的非递归写法。

如何实现?

抽象出递归公式、初始值,和边界条件,然后用迭代循环实现。

引用

《王争——数据结构和 算法之美》

你可能感兴趣的:(递归)