递归的定义
递归(recursion)
就是函数调用自身的一种方式,具体第一参见递归百度百科
如何理解递归
大家中学都学过数列,递归其实类似于数列,本质就是这一次与下一次之前的关系,只要找准二者之间的关系,便可以很好的理解递归调用,因为递归是调用本身,所以解决的一定是相同的问题,而又必须满足又穷性,所以需要有结束条件(通常是使其规模更小),切记,千万不要一层一层跟着走,就像你在解决数列问题时更需要找到通项公式而不是一个一个去列举出来。
0x1 求N个数的和
大家都知道N个数的和的通项公式是,如果直接求值,用这个公式会比较简单,但如果递归的思考这个问题,很容易写出下面的式子
为了求n个数的和,就需要先求n-1个数的和,正如前面所说,n与n-1必须解决相同的问题,但规模更小,这里明显满足,都是求k个数的和,规模k由n变为了n-1。我们写出如下代码
def sum(n):
if n == 1: # 结束条件,对于n个数来说,首项默认为1
return 1
else:
return n + sum(n-1) # S_n = S_{n-1} + n
0x2 斐波拉契数列
根据百度百科其通项公式为,这里我们会更进一步的思考递归的本质及其过程,上面已经给出了通项公式,所以利用0x1
的思想,很容易就能写出代码,但我们不妨思考一下数列的通项公式,数列的通项公式本质就是一个函数(function)
,他的输入是n,函数值是第N项的数列的值,所以我们还可以这样思考假设现在我们有了一个函数frac
,他的参数是n,返回值是第n项的值,那么我们把这个通项公式换成python代码就是
frac_N = frac(n-1) + frac(n-2)
现在我们列出了,相邻两个规模的关系,现在我们需要思考其结束条件,根据斐波拉契的定义,其首两项分别为1和1,所以写出完整代码如下
def frac(n):
if n == 1:
return 1
if n == 2: # 结束条件
return 2
return frac(n-1)+frac(n-2) #第n项等于n-1项加n-2项
0x3 汉诺塔
先看看汉诺塔问题的描述:
汉诺塔(Tower of Hanoi),又称河内塔。源自印度古老传说的一个游戏,大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
根据0x1和0x2所说,如何思考这样一个问题呢?结合二者的思想,那么我们首要目标就是验证它是否可以用递归解决,也就是这一次和下一次是否面临同样的问题(是否能写出通项公式),让我们仔细思考一下,假设现在有A,B,C三个柱子,现在要想把N块圆盘从A移动到C,根据规则,小盘不能在大盘上,那么我们就得先把N-1个小盘移动到B上,然后把第N个盘(也就是最大的那块)移动到C上,再将N-1块盘从B上移动到C。那么我们如何让N-1个盘从A移动到B上呢?先得把N-2个盘从A移动到C上,再把第N-1个盘移动到B上。假设我们现在有这样一个函数hanoi(n,start,helper,target)
可以解决这样一个问题,他的输入参数是盘的规模N,三个柱子A,B,C,它的作用是把n块盘从起始位置start
移动到目的位置target
,中间借助位置helper
,那么根据我们的分析,把N快盘从A,借助B移动到C的代码为
hanoi(n,'A','B','C')
根据上面分析先得把N-1个小盘移动到B上,然后把第N个盘(也就是最大的那块)移动到C上,代码为
hanoi(n-1,start=start,helper=target,target=helper) #将k-1块圆盘从start移动到helper先放着,
print(f"将第{n}块盘从{start}直接移动到{target}") #将第k块圆盘直接从start移动到target
hanoi(n-1,start=helper,helper=start,target=target) #再将放在helper那里的k-1块盘从helper移动到target
最后一步,想想结束条件是什么呢?当直接最后一块盘,也就是最上面的那块,当然是直接移动过去即可,所以完整代码为:
def hanoi(n,start="A",helper="B",target="C"):
if n == 1:
print(f"将第{n}块盘从{start}直接移动到{target}") #将最上面的那块圆盘直接从start移动到target
else:
hanoi(n-1,start=start,helper=target,target=helper) #将k-1块圆盘从start移动到helper先放着,
print(f"将第{n}块盘从{start}直接移动到{target}") #将第k块圆盘直接从start移动到target
hanoi(n-1,start=helper,helper=start,target=target) #再将放在helper那里的k-1块盘从helper移动到target
运行结果: