Skip to content

Latest commit

 

History

History
73 lines (48 loc) · 3.36 KB

递归.md

File metadata and controls

73 lines (48 loc) · 3.36 KB

递归相关的算法

这里只做思路分析,具体实现请看js/recursive.js

  1. 台阶问题
  2. 链式函数
  3. 汉诺塔问题

台阶问题

假设一个楼梯有n个阶台阶,人每次最多可以跨m个台阶,编写函数fn(n, m)输出所有的爬楼梯方案。

还是先手动走下流程:

例如楼梯总共有4个台阶,人每次最多跨3个台阶,也就是说人每次可以走1个 、2个或者3个台阶,那么楼梯总共有这么几种走法:31, 22, 211, 13, 121, 112, 1111。

流程分析一下:

  1. 当前有n个台阶,如果n>m则先用最大步数m去走, 再换m-1,再换m-2直到1;如果n<m,那么就先用n去走,然后换n-1、n-2。。。
  2. 走完1之后剩下的台阶再用1的规则去套。。。

退出条件是什么呢?n=0时,代表一个走法走完了。

总结: for [1 m]: if (n == 1): step = 1 if (n < m): go(n, n) if (n >= m): step = m, go(n-m, m)

链式函数

编写阶乘函数 fn,使得 fn(2)(3) = 6,fn(2)(3)(4) = 24

显然,fn(2)应该返回一个函数temp,而temp(3)返回一个函数ttemp,那最后输出的值实际上就是ttemp.valueOf的调用。

temp函数是怎样的呢:def temp(x): fn(x * y)

function mul(x) {
  const fn = y => mul(x * y);  // 返回一个函数,函数参数里面做乘法运算
  fn.valueOf = () => x;  // 改写valueOf,在链式运算最后一步输出结果
  return fn;
}

汉诺塔问题

汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

这里要构造一个输出移动过程的函数move(n, a, b, c),其中n为a柱子的数量,a, b, c分别代表三根柱子,a为源柱子、b为过渡柱子、c为目标柱子。

函数调用方式:'A'柱子有5个盘子,全移动到'C',调用(5, 'A', 'B', 'C');全移动到'B',则调用(5, 'A', 'C', 'B');

使用递归的思路,自然就是想着从最后一步倒推n-1步了。当我们手动尝试了n=[1, 4]的情况后,基本就知道这个套路应该是怎样的了。

  1. 当我们要移动a柱子的最大盘子n到c的话,那这一步的前提肯定是:比n小的盘子都在b上,我们才能将n号盘从a --> c,这个场景也就是n=1的情况。
  2. 接着就是如何将b中的n-1号盘移动到c呢?这一步就不用考虑n号盘了,因为他已经就位了,那这一步前提肯定是,比n-1小的盘子都在a上了,咦,这里不就是1的翻版吗?递归的规律已经出来了。
  3. 然后想想怎么才能得到1这种局面呢?显然,就是要将n-1个盘子从a移动到b上面,怎么做?重复1和2不就完了?

所以盘子移动的套路就是:

  1. 将n-1个盘子从a移动到b:move(n-1, a, c, b)
  2. 将n号盘从a移动到c:move(1, a, b, c)
  3. 将n-1个盘子从b移动到c:move(n-1, b, a, c)

退出条件?n=1呗,n=1的时候,那自然就是a --> c

总结:

if n == 1: `a --> c`
else: move(n-1, a, c, b) move(1, a, b, c) move(n-1, b, a, c)