递归:递推公式

1. 递推公式

证明 f ( n ) = 5 n + 3 f(n)=5^n+3 f(n)=5n+3可以被4整除
先看几个具体的case,看看能不能被4整除

n n n f ( n ) = 5 n + 3 f(n)=5^n+3 f(n)=5n+3
n = 1 n=1 n=1 f ( 1 ) = 5 1 + 3 = 8 f(1)=5^1+3=8 f(1)=51+3=8
n = 2 n=2 n=2 f ( 2 ) = 5 2 + 3 = 28 f(2)=5^2+3=28 f(2)=52+3=28
n = 3 n=3 n=3 f ( 3 ) = 5 3 + 3 = 128 f(3)=5^3+3=128 f(3)=53+3=128

查看了几个case发现都是可以被4整除的,那么如何证明任意一个n都可以让 5 n + 3 5^n+3 5n+3被4整除呢?前面通过实际的数据表明n=3的时候是可以被4整除的,那么n=4可以被4整除吗
f ( 4 ) = 5 4 + 3 = 5 × 5 3 + 3 = 4 × 5 3 + 5 3 + 3 = 4 × 5 3 + f ( 3 ) \begin{aligned} f(4) & =5^4+3\\ & =5\times 5^3+3\\ &=4\times 5^3+5^3+3\\ &=4\times 5^3+f(3) \end{aligned} f(4)=54+3=5×53+3=4×53+53+3=4×53+f(3)

可以发现 4 × 5 3 4\times 5^3 4×53可以被4整除,而且 f ( 3 ) f(3) f(3)也是可以被4整除的,因此 f ( 4 ) f(4) f(4)可以被4整除。更一般的有递推公式
f ( k + 1 ) = 5 k + 1 + 3 = 5 × 5 k + 3 = 4 × 5 k + 5 k + 3 = 4 × 5 k + f ( k ) \begin{aligned} f(k+1) & =5^{k+1}+3\\ & =5\times 5^k+3\\ &=4\times 5^k+5^k+3\\ &=4\times 5^k+f(k) \end{aligned} f(k+1)=5k+1+3=5×5k+3=4×5k+5k+3=4×5k+f(k)

递推公式已经被我们写出来了,可以看到如果 f ( k ) f(k) f(k)可以被4整除,那么 f ( k + 1 ) f(k+1) f(k+1)就一定可以被4整除。我们从1开始计算

  • 1可以被4整除,那么一定有2可以被4整除
  • 2可以被4整除,那么一定有3可以被4整除

依次进行下去,也就是说任意一个整数都可以符合。

2. 如何求解 n ! n! n!

再看一个问题,如何求解 n ! n! n!,这个问题也非常的简单,我们直接从1开始一直乘到n就可以得到了

res = 1
for i in range(1,n+1):
    res *= i

我们这里可以考虑递归,说白了就是求递推公式,我们也从最简单的n=1开始计算

n n n f ( n ) = n ! f(n)=n! f(n)=n!
n = 1 n=1 n=1 f ( 1 ) = 1 f(1)=1 f(1)=1
n = 2 n=2 n=2 f ( 2 ) = 1 ∗ 2 f(2)=1*2 f(2)=12
n = 3 n=3 n=3 f ( 3 ) = 1 ∗ 2 ∗ 3 f(3)=1*2*3 f(3)=123
n = 4 n=4 n=4 f ( 4 ) = 1 ∗ 2 ∗ 3 ∗ 4 f(4)=1*2*3*4 f(4)=1234
n = 5 n=5 n=5 f ( 5 ) = 1 ∗ 2 ∗ 3 ∗ 4 ∗ 5 f(5)=1*2*3*4*5 f(5)=12345

更一般的递推公式有
f ( n ) = f ( n − 1 ) ∗ n f(n)=f(n-1)*n f(n)=f(n1)n

也就是说我想要求解 f ( n ) f(n) f(n),那么我只需要把 f ( n − 1 ) f(n-1) f(n1)求解出来即可,但是为了求解 f ( n − 1 ) f(n-1) f(n1),我需要把 f ( n − 2 ) f(n-2) f(n2)求解出来,说白了就是不断的套娃。简单看一下 f ( 6 ) f(6) f(6)是如何计算
f ( 6 ) = 1 ∗ 2 ∗ 3 ∗ 4 ∗ 5 ∗ 6 = f ( 5 ) ∗ 6 = f ( 4 ) ∗ 5 ∗ 6 = f ( 3 ) ∗ 4 ∗ 5 ∗ 6 = f ( 2 ) ∗ 3 ∗ 4 ∗ 5 ∗ 6 = f ( 1 ) ∗ 2 ∗ 3 ∗ 4 ∗ 5 ∗ 6 = 1 ∗ 2 ∗ 3 ∗ 4 ∗ 5 ∗ 6   \begin{aligned} f(6)&=1*2*3*4*5*6\\ &=f(5)*6\\ &=f(4)*5*6\\ &=f(3)*4*5*6\\ &=f(2)*3*4*5*6\\ &=f(1)*2*3*4*5*6\\ &=1*2*3*4*5*6\ \end{aligned} f(6)=123456=f(5)6=f(4)56=f(3)456=f(2)3456=f(1)23456=123456 

老实说这有种脱裤子放屁的感觉,还不如直接从1开始直接乘到n,这个case是没有任何问题的,不过越往后case会越复杂,也越会接近递归。我们先用递归的方式写出来

def f(n):
	if n == 1:return 1
    return f(n-1)*n

3. 如何求解 x n x^n xn

这个问题也是非常的简单,我们依然通过循环就可以解决

def f(x,n):
    res = 1
    for _ in range(n):
    	res *= x
    return res

同样可以写出递推公式
f ( n ) = f ( n − 1 ) ∗ x f(n)=f(n-1)*x f(n)=f(n1)x
写出他的递归方法

def f(x,n):
	if n == 0:
		return 1
	return f(x,n-1)*x

同样这个case也是脱裤子放屁,明明可以用循环解决为什么要考虑使用递归呢?因为有一种巧妙的解决方法,我们把递归公式改一改
f ( n ) = { f 2 ( ⌊ n 2 ⌋ ) n % 2 = = 0 f 2 ( ⌊ n 2 ⌋ ) ∗ x n % 2 = = 1 f(n)= \begin{cases} f^2(\lfloor \frac{n}{2}\rfloor) & n\%2==0 \\ f^2(\lfloor \frac{n}{2}\rfloor)*x & n\%2==1 \end{cases} f(n)={f2(⌊2n⌋)f2(⌊2n⌋)xn%2==0n%2==1
这个方法不是我想出来的,但是看到之后觉得非常的巧妙。我们看一下 f ( 13 ) f(13) f(13)怎么求。

f ( 13 ) f(13) f(13) f 2 ( 6 ) ∗ x f^2(6)*x f2(6)x 13 % 2 = 1 13 \% 2=1 13%2=1
f ( 6 ) f(6) f(6) f 2 ( 3 ) f^2(3) f2(3) 6 % 2 = 0 6 \% 2=0 6%2=0
f ( 3 ) f(3) f(3) f 2 ( 1 ) ∗ x f^2(1)*x f2(1)x 3 % 2 = 1 3 \% 2=1 3%2=1
f ( 1 ) f(1) f(1) f 2 ( 0 ) ∗ x f^2(0)*x f2(0)x 1 % 2 = 1 1 \% 2=1 1%2=1
f ( 0 ) f(0) f(0) 1 1 1base

也就是说,我们现在只需要求解 f ( 1 ) , f ( 3 ) , f ( 6 ) , f ( 13 ) f(1),f(3),f(6),f(13) f(1),f(3),f(6),f(13)只需要求解4次就可以得到结果了,而如果使用循环的话,我们则需要求解13次,高下立判。
这个case说明了一个问题,不同的递推公式,会得到不同的求解复杂度。在这个case中,常规的递推公式是一步一步的缩小问题求解规模的,也就是得到 f ( n ) f(n) f(n) f ( n − 1 ) f(n-1) f(n1)的关系,然后每次减少1来不断缩小问题规模,但是修改之后得到的是 f ( n ) f(n) f(n) f ( n / / 2 ) f(n//2) f(n//2)的关系,每次是 n / / 2 n//2 n//2的指数方式缩小问题规模。

4. 斐波那契数列

1、楼梯问题:一个阶梯共n级,刚开始时人在第1级,若每次只能跨一级或两级,要走上第n级,共有多少种走法?
假如现在有5阶楼梯,我们给每一阶楼梯编码1,2,3,4,5。从最简单的case开始算起
当n=1时,只有一种方法
当n=2时,可以一步一步跳上去,也可以直接跳上去1-2,2
当n=3时,一步一步跳上去,或者先跳上去两层,然后再上去一层,或者先走一层再跳上去两层1-2-3,1-3,2-3

你会发现从前往后算是非常复杂的,这个问题可以从后往前思考。例如当n=4时,如果想要跳上去,只能从2和3两个台阶跳上来, f ( 2 ) = 2 , f ( 3 ) = 3 f(2)=2,f(3)=3 f(2)=2,f(3)=3,所以跳到4阶台阶时有 f ( 4 ) = f ( 2 ) + f ( 3 ) = 5 f(4)=f(2)+f(3)=5 f(4)=f(2)+f(3)=5种方式。我之前一直考虑的一个问题时,为什么是两种方法的相加,为什么不是想乘或者其他的结合方式呢?我把递归树给绘制了一下,每个圆圈中的值就是这个台阶的名称,0表示地面,每一条路径就是一种跳上去的方法。例如最左侧的这条路径0-1-2-4-5,

  • 先跳1步到1上面去,
  • 然后再跳1步到2上面去,
  • 然后再跳2部跳到4上面去,
  • 最后再跳1步跳到5上面去。

可以看到最上面的节点4有5条路径,节点3有3条路径,所以节点5总共就有3+5=8条路径,因此就是相加的关系
在这里插入图片描述
根据上面的分析很容易写成递推公式
f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n)=f(n-1)+f(n-2) f(n)=f(n1)+f(n2)

可以很容易的写成递归方法

def f(n):
	if n == 1:return 1
	if n == 2:return 2
	return f(n-1)+f(n-2)

如果用递归,你会发现一个问题,就是很多节点都重复计算了,因此考虑直接使用循环来解决

def f(n):
	fn1 = 1
	fn2 = 2
	fn = 0
	for i in range(3,n+1):
		fn = fn1+fn2
		fn2 = fn1
		fn1 = fn

2、矩形覆盖问题:用1×2的小矩形覆盖2×n的大矩形,总共有多少种方法?
这个问题跟斐波那契数列如出一辙,绘制出来也非常容易理解。假如n=5,如果想要全部填充完成,有两种方式,一种是将前4个填充完,最后补一个就行,或者就是将前3个填充完,最后需要补两个
在这里插入图片描述

5. 小总结

上面的递推问题,本质都是不断减小问题规模,要求 f ( n ) f(n) f(n),先求出较小规模的 f ( n − 1 ) , f ( n / / 2 ) f(n-1),f(n//2) f(n1),f(n//2)等等,所以,最重要的就是如何分析问题得到递推公式。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值