[算法系列] 深入递归本质+经典例题解析——如何逐步生成, 以此类推,步步为营

[算法系列] 深入递归本质+经典例题解析——如何逐步生成, 以此类推,步步为营

本文是递归系列的第三篇, 第一篇介绍了递归的形式以及递归设计方法(迭代改递归),;第二篇以递归为引子, 详细介绍了快排和归排以及堆排的核心思想; 本篇主要通过几个题, 从递推, 归纳法的角度, 深入了介绍了递归的本质和具体应用.

往期回顾:

  1. 搞懂递归, 看这篇就够了 !! 递归设计思路 + 经典例题层层递进
  2. 递归应用: 快速排序+归并排序算法及其核心思想与拓展 … 附赠 堆排序算法

回顾我们在第一篇文章讨论的递归中, 下面是我们能够看到现象形式:

f(n) -> f(n - 1) -> f(n-2) -> ... -> f(1)

但实际本质是: 为了解决/完成 f(n), 必先完成f(n- 1); 为解决f(n-1),必先解决f(n-2) … 那么最先要解决f(1)

f(1) -> f(2) -> f(3) -> ... ->f(n)

回顾以前学过的数学归纳法:

1. 证明当k=1时,条件成立
2. 假设k=n(n>=1)时,条件成立
3. 证明k=n+1,条件成立
得到结论: k取任意正整数时,条件成立

如果没记错的话这叫第一数学归纳法, 往往我们用来证明构造的某些式子在给定自然数集合(全体或局部)的正确性. 而数学归纳法本质是什么呢? 通俗来看, 就是首先证明了k=1时的正确性, 然后证明k = n 成立可以推导出k=n+1成立. 根据上述两个条件可以得出k=2也就成立了… 然后k=3也就成立… 本质是递推.

  • 递归解决的本质是先从f(1)->f(2)->…->f(n), 小问题解决了,再解决大问题
  • 数学归纳法式从k = 1 逐层证明, 或者说证明k=n和k=n+1的关系,然后递推
  • 递推, 就是按照前一个(或几个)的关系推理出下一个 …

recursion一词既可以翻译为递推,也可以翻译为递归, 这里的归应该是是规约的意思. 注意这里的递归和编程形式中的 递归调用 是有点区别的, 编程中谈到的形式化更多一些, 而数学本质还是和递归递推没有区别.

递归, 递推, 数学归纳法本质正是同一种东西.

好了,现在看来知道了这些似乎作用不大. 我们还是举个例子, 搞懂递归, 看这篇就够了 !! 递归设计思路 + 经典例题层层递进 中的青蛙上楼梯问题.

1. 再谈青蛙上楼梯

楼梯有n个台阶, 一个青蛙一次可以上1 , 2 或3 阶 , 实现一个方法, 计算该青蛙有多少种上完楼梯的方法

文中给出了递归的解法:

(回忆找重复,找变化,找出口)

假如青蛙上10 阶, 那么其实相当于要么 站在第9 阶向上走1步,要么 站在第8 阶向上走两步, 要么在第7阶向上走3步. 每个大于3阶楼梯的问题都可以看成几个子问题的堆叠

变化:令f(n) 为 青蛙上n阶的方法数. 则f(n) = f(n -1) +f(n - 2) + f(n -3) , 当n >= 3

出口: 当n = 0 时 ,青蛙不动 , f(0) = 0; n = 1时 ,有1种方法 , n = 2 时 有2 种方法

def f(n):
    if n == 0 :
        return 1	#站着不动也得返回1的, 因为实际上0种方法的是没意义
    if n == 1:
        return 1
    if n == 2:
        return 2
    return f(n - 1) +f(n - 2) +f(n -3)

显然这样的递归方法不是很直观的, 其实一开始拿到这题 , 普通地想, 应该是拿出张白纸来, 左边起名一列: 阶数 , 右边起名一列: 走法

阶数		走法
1			1		0->1
2			2		0->1->2			0->2		
3			4		0->1->2->3		0->1->3		0->2->3		0->3		
4			7		...						
...			...

详细康康阶数为4时的走法:

在这里插入图片描述

注意我分成了三列写, 如果不看红色部分的话, 三列分别代表了上第1,2,3阶的方法. 现在带着红色的 ->4 一起看:

  • 第一列: 相当于先上到第1阶再一次上到4 (因为最大可以跨3阶嘛)
  • 第二列: 相当于先上到第2阶再一次上到4 (相当于最后一次跨2阶嘛)
  • 第三列:相当于先上到第3阶再一次上到4(最后一次跨1阶即可)

显然上到第四阶的方法刚好就是这三列的和了 …

到这里, 有兴趣的同学可以在写出阶数为5的走法. 但其实也会得到下面的结论:

  • 第一列: 相当于先上到第2阶再一次上到5 (因为最大可以跨3阶嘛)
  • 第二列: 相当于先上到第3阶再一次上到5 (相当于最后一次跨2阶嘛)
  • 第三列:相当于先上到第4阶再一次上到5(最后一次跨1阶即可)

显然上到第五阶的方法刚好就是这三列的和了 …

…想一想, 规律也就可以得出了

阶数为n的走法. 但其实也会得到下面的结论:

  • 或者先上到第n-3阶再一次上到n (因为最大可以跨3阶嘛)
  • 或者先上到第n-2阶再一次上到n (相当于最后一次跨2阶嘛)
  • 或者于先上到第n-1阶再一次上到n(最后一次跨1阶即可)

所以 f(n) = f(n -1) +f(n - 2) + f(n -3) 不是凭空产生, 而真是一步一步的像上面一样推出来 – 递归表达也是如此

下面就可以自然的得到递归法实现

def go_stairs(n):
    if n <= 1:
        return 1
    if n == 2 :
        return  2
    if n == 3 :
        return  4
    return go_stairs(n - 1) + go_stairs(n - 2) + go_stairs(n - 3)

写出了出口条件, 写出了递推式, 计算机不就帮我们像上面一样, 一步一步地推下去了么…

同样的, 我们也可以按照我们的推理演算的顺序, 用一个长度为3的数组, 保存每次得到的f(n -1) ,f(n - 2) ,f(n -3), 下一轮再更新…这就是我们递推的迭代法实现 :

def go_stairs_ite(n):
    #声明一个长度为4的数组保存每次计算得到值, 用于存储每次计算所需的三个值和一个结果值
    arr =[]
    if n <= 1:
        return 1
    if n == 2 :
        return  2
    if n == 3 :
        return  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值