递归三部曲

708 阅读4分钟

递归三部曲

这里帮助大家确定下来递归算法的三个要素。每次写递归,都按照这三要素来写,可以保证大家写出正确的递归算法!

  1. 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
  1. 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
  1. 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。

好了,我们确认了递归的三要素,你只需要明确本层递归函数返回的是什么,或者做了什么操作,其他的不用你管,不需要一步步带入递归,会陷入地狱,抛给递归三部曲,递归会对所有节点做相同的操作。接下来就来练练手:

深拷贝

  • 确定递归函数的参数和返回值:因为函数的功能就是深度拷贝一个数据,所以参数需要传入需要拷贝的原始数据,返回值就是深度拷贝之后的数据:代码如下
function deepCopy(oldObj) {
  ...
  return copy
}
  • 确定终止条件:在递归的过程中,如何算是递归结束了呢,当然是遍历原始数据结束之后,那么本层递归就要要结束了,所以遍历之后,就直接return copy,代码如下:
function deepCopy(oldObj) {
  let copy = oldObj instanceof Array ? [] : {}
  for (let k in oldObj) {
    ...
  }
  return copy
}
  • 确定单层递归的逻辑:因为deepCopy这个函数返回的就是深拷贝过后的数据,所以遍历过程中,如果判断是引用类型就需要调用deepCopy进行深拷贝,代码如下(注意判断引用类型需要先判断数组之后再是对象,因为数组也是对象):
if (oldObj[k] instanceof Array) {
  copy[k] = deepCopy(oldObj[k])
} else if (oldObj[k] instanceof Object) {
  copy[k] = deepCopy(oldObj[k])
}
  • 单层递归的逻辑就是判断数据是否是引用类型,如果是则递归,这样基本就写完了,再看一下完整代码:
function deepCopy(oldObj) {
  let copy = oldObj instanceof Array ? [] : {}
  for (let k in oldObj) {
    if (oldObj[k] instanceof Array) {
      copy[k] = deepCopy(oldObj[k])
    } else if (oldObj[k] instanceof Object) {
      copy[k] = deepCopy(oldObj[k])
    } else {
      copy[k] = oldObj[k]
    }
  }
  return copy
}

斐波那契数列

斐波那契数 形成的序列称为 斐波那契数列 。该数列由 01 开始,后面的每一项数字都是前面两项数字的和。也就是:

0、1、1、2、3、5、8、13、21...

要求封装函数输入 n ,就可以得到第 n 个斐波那契数

  • 确定递归函数的参数和返回值:因为函数的功能就是得到第 n 个斐波那契数,所以参数需要传入 n,返回值就是第 n 个斐波那契数:代码如下
function fib(n) {
  ...
  return curr // curr 代表第 n 个斐波那契数
}
  • 确定终止条件:第0个数 = 0,第1个数 = 1,第2个数 = 第0个数 + 第1个数(1 = 0 + 1),第3个数 = 第1个数 + 第2个数(2 = 1 + 1),从第2个数都需要根据之前的两个数来得到结果,第0、1个数直接有值,所以如果 n 是 0 或 1不用递归,直接返回值,代码如下:
function fib(n) {
  if(n <= 1) return n
  ...
  return curr
}
  • 确定单层递归的逻辑:从第2个数开始都需要根据之前的两个数来得到结果,因为fib函数本来就是返回第 n 个 斐波那契书,所以需要调用 fib 函数获取,代码如下:
let pre1 = fib(n - 1) //pre1代表第n个的前一个数
let pre2 = fib(n - 2) //pre2代表第n个的之前第二个数
let curr = pre1 + pre2 //curr 代表第 n 个斐波那契数
  • 这样基本就写完了,再看一下完整代码:
function fib(n) {
  if(n <= 1) return n
  let pre1 = fib(n - 1)
  let pre2 = fib(n - 2)
  let curr = pre1 + pre2
  return curr
}
​
// 简化代码
function fib(n) {
  if(n <= 1) return n
  return fib(n - 1) + fib(n - 2)
}
// 可以动态规划优化代码,这里不做讨论

力扣有相关题目:509. 斐波那契数 - 力扣(LeetCode)