注:今天博主开始更新数据结构与算法中的排序算法系列,使用Python语言实现,涉及基本数据结构、十大排序算法、递归分治、贪心动归等,意在帮大家更加容易的学习数据结构与算法以及进一步梳理这些知识点。
目录
递归的组成结构
首先来了解一下冰桶游戏:参与者在网 络上发布自己被冰水浇遍全身的视频内容,然后邀请3位朋友参加该活动
朋友要么24小时内接受挑战,要么选择向对抗“渐冻症”组织捐款100美元,仅在美国就有170 万⼈参与挑战,250 万⼈捐款,总⾦额达1.15 亿美元
如何凑集一笔巨款用于公益事业?
- 找朋友(众人拾材火焰高)
- 确定策略(朋友愿意帮你)
- 如何说服朋友愿意帮你
- 募捐到你额度的⼗分之⼀
如果你需要募集100 万,那么他们各⾃需要募集10 万,他们不需要真的捐钱,而是按照你给的策略去募集10万,把你的方法传递下去。筹款的算法如下:
算法代码
def collect_contributions(n):
#n为需要筹集的款数
if (n<=100):
return 100 #需要此人捐出100元
else:
#寻找10个朋友
friends= find_friend()
sum = 0
for i in range(len(friends)):
# 从这10个朋友中分别募集n/10元
sum += collect_contributions(n/10)
return sum
总结
- 分解问题(找朋友)
- 递归求解(相同的策略)
- 边界条件(求解/计算)
递归算法的两个要素:
- 必须有最终停⽌发展下线的边界条件,否则无穷循环
- 必须有与原始问题结构⼀致,但输⼊规模⼩于原始问题规模的递归结构
递归算法的执行
斐波那契《算盘书》:⼀对兔⼦饲养在围墙中,如果它们每个⽉⽣⼀对兔⼦,且新⽣的兔⼦在第⼆个⽉后也是每个⽉⽣⼀对兔⼦,问⼀年后围墙中共有多少对兔⼦。斐波那契的分析如下:第⼀个⽉是最初的⼀对兔⼦⽣下⼀对兔⼦,围墙内共有两对兔⼦;第⼆个⽉仍是最初的⼀对兔⼦⽣下⼀对兔⼦,共有3对兔⼦;到第三个⽉除最初的兔⼦新⽣⼀对兔⼦外,第⼀个⽉⽣的兔⼦也开始⽣兔⼦,因此共有5 对兔⼦。第24 个⽉共有⼏对兔⼦?
斐波那契序列
算法代码
def fib_rec(n):
if n <= 1:
f = n
else:
f = fib_rec(n-1) + fib_rec(n-2)
return f
if __name__ == '__main__':
num = 24
print('fib({0})==>{1}'.format(num,fib_rec(num)))
跟踪递归函数的执行过程
求斐波那契序列算法的时间复杂度
利用递归算法求解问题-判断回文
回文定义: ⼀个正向和反向读是相同的字符串
- level,noon
- 蜜蜂酿蜂蜜,静泉⼭上⼭泉静,上海⾃来⽔来⾃海上
当给定⼀个字符串str,需要判断该字符串是否为回⽂<如果是回⽂返回True,否则返回False
简单实现:时间复杂度为O(n)
递归实现
不妨设已经有⼀个函数 is_palindrome(s)可以⽤来求解该问题,不妨设 s=’level’
def is_palindrome(s):
if len(s) <= 1:
return True
else:
return s[0] == s[-1] and is_palindrome(s[1:-1])
第2行边界条件,第5行递归。时间复杂度为o(n)。
利用递归算法求解问题-全排列
输⼊的字符s=“ABC”,由字符A,B 和C 组成的全排列为:[“ABC”, “ACB”, “BAC”, “BCA”, “CAB”, “CBA”]
不妨设求解原问题的函数为permutation(s),如何将问题进行分解形成子问题,从而可以寻求朋友的帮助?
def permutation(str):
lenstr = len(str)
if lenstr < 2:#边界条件
return str
else:
result = []
for i in range(lenstr):
ch = str[i] #取出str中每一个字符
rest = str[0:i] + str[i+1:lenstr]
for s in permutation(rest): #递归
result.append(ch + s) #将ch与子问题的解依次组合
return result
对于长度为n 的输⼊字符串,共有n! 个全排列,因此代码的时间复杂度为O(n!)
利用递归算法求解问题-汉诺塔问题
每次只能移动⼀个盘⼦,移动过程中,⼩的盘⼦不能处于⽐它⼤的盘⼦下⾯
不妨设有函数hanoi( )可以求解该问题,函数参数如何设计?
函数hanoi(n, S=‘A’, T=‘B’,H=‘C’) 可以求解该问题,其中n 为盘⽚数,A, B 和C 分别为三个柱⼦,S 表⽰出发的柱⼦,T 为⽬的柱,H 为过渡⽤柱⼦
def hanoi(n,source,target,helper):
if n==1: # 边界条件
moveSingleDesk(source,target)
else:
hanoi(n-1,source,helper,target) # 将n-1个盘从A移到C
moveSingleDesk(source,target) # 将A中最大的一个盘从A移到B
hanoi(n-1,helper,target,source) # 将n-1个盘从C移到B
def moveSingleDesk(source,target):
disk = source[0].pop()
print("moving " + str(disk) + " from " + source[1] + " to " + target[1])
target[0].append(disk)
利用递归算法求解问题-雪花曲线
瑞典⼈科赫于1904年提出了著名的“雪花”曲线
- 如果n=0,直接画出L 长的直线即可。如果n=1(第⼀次迭代),画出长度为L/3 的线段;画笔向左转60 度再画长度为L/3 长的线段;画笔向右转120 度画长度为L/3 长的线段;画笔再向左转60 度画出长度为L/3 的线段。
- 如果n>1,第n 次迭代相当于:第n-1 次迭代;画笔左转60 度;n-1 次迭代;画笔右转120 度;第n-1 次迭代;画笔左转60 度;第n-1 次迭代。
- 其中,第n >1 次迭代线段长度为L,第n 次迭代时线段长度则为L/3
import turtle
def koch(t,order,size):
if order ==0: # 边界条件
t.forward(size)
else:
koch(t,order-1,size/3) # 递归调用
t.left(60) # 笔转60度
koch(t,order-1,size/3) # 递归调用
t.right(120) # 笔转120度
koch(t,order-1,size/3) # 递归调用
t.left(60) # 笔转60度
koch(t,order-1,size/3) # 递归调用
相应面试题可参考如下内容或者前往公众号查看更多内容: