递归Recursion
递归是一种解决问题的方法;算法方面的明显特征就是调用自身。
- 将问题分解为规模更小的相同问题;
- 持续分解,直到问题规模小到可以用非常简单直接的方式来解决。
#数列求和
def listsum(numlist):
theSum = 0
for i in numlist:
theSum += i
return theSum
print(listsum([1,2,3,4,5]))
接下来我们用递归来进行数列求和;
(1+(2+(3+(4+5))))
(1+(2+(3+9)))
(1+(2+12))
(1+14)
15
数列的和=‘首个数’+‘余下数列’的和。
def listsum(numlist):
if len(numlist) == 1:
return numlist[0]
else:
return numlist[0] + listsum(numlist[1:])
print(listsum([1, 2, 3, 4, 5]))
使用debug功能可以看到函数调用的过程。
递归三定律:
- 递归算法必须有一个基本结束条件(最小规模问题的直接解决);
- 递归算法必须能改变状态向基本结束条件演进(减小问题规模);
- 递归算法必须调用自身(解决减小了规模的相同问题)。
递归的应用
整数转换为任意进制(递归与栈)
比如;
857 // 10 = 85 | 857 % 10 =7
85 // 10 = 8 | 85 % 10 = 5
8 // 10 = 0 | 8 % 10 = 8
- 结束条件:余数小于进制数;
- 整数商称为更小规模问题,调用自身;
上次我们用栈来实现了进制转换,需要的可以去回看。
栈及其python实现:https://blog.csdn.net/suwuzs/article/details/121450086
def toConverter(num,base):
converString = '0123456789ABCDEF'
if num < base:
return converString[num]
else:
return toConverter(num//base,base) + converString[num%base]
print(toConverter(20,16))
print(toConverter(8,2))
输出:
14
1000
递归调用;
- 当一个函数被调用的时候,系统会把调用时的现场数据压入到系统调用栈;
- python中的递归深度限制;可以通过sys.getrecursionlimit()获取调整最大递归深度。
LeetCode面试题 08.06. 汉诺塔问题
汉诺塔是法国数学家Edouard Lucas于1883年提出的。我们从递归三定律;基本结束条件,如何减小规模,调用自身;来分析汉诺塔问题。
三个柱子**#1(fromPole)、#2(withPole)、#3(toPole)**。
- 首先将上层n-1个盘片移到#2柱,然后将第n个盘子移到#3柱,然后再将#2柱上的n-1个盘子移到#1柱上;
- 直到还剩一个盘子在#1柱上时,直接移到#3柱,移动结束;
- 基本结束条件,也就是最小规模问题,1个盘片的移动。
def Hanota(height, fromPole, withPole, toPole):
if height >= 1:
Hanota(height-1, fromPole, withPole, toPole)
moveDisk(height, fromPole, toPole)
Hanota(height-1, withPole, fromPole, toPole)
def moveDisk(disk, fromPole, toPole):
print(f'moving disk[{disk}] from {fromPole} to {toPole}')
Hanota(3,'#1','#2','#3')
输出:(打印出移动过程)
moving disk[1] from #1 to #3
moving disk[2] from #1 to #3
moving disk[1] from #2 to #3
moving disk[3] from #1 to #3
moving disk[1] from #2 to #3
moving disk[2] from #2 to #3
moving disk[1] from #1 to #3