递归是一种解决问题的方法,其精髓在:
将问题分解为规模更小的相同问题
持续分解,直到问题规模小到可以用非常简单直接的方式解决
递归的问题分解方式非常独特,其算法方面的明显特征就是:在算法流程中调用自身
递归为我们提供了一种对复杂问题的优雅解决方案,精妙的递归算法常会出奇简单,令人赞叹。
def listsum(numList):
if len(numList) == 1:
return numList[0]#更小规模
else:
return numList[0] + listsum(numList[1: ])#调用自身
print(listsum[1,3,5,7,9])
问题分解为更小规模的相同问题,并表现为"调用自身";对更小规模问题的解决:简单直接
调用递归时常出现的错误:RecursionError
递归的层数太多,系统调用栈容量有限
这时候要检查程序中是否忘记设置基本结束条件,导致无限递归
或者向基本结束条件演进太慢,导致递归层数太多,调用栈溢出
在python内置的sys模块可以获取和调整最大递归深度
import sys
sys.getrecursionlimit()#获取递归深度
sys.setrecursionlimit(3000)#修改递归深度
作图模板
#1.导入海龟模块
import turtle
#2.生成一只海龟,做一些设定
t = turtle.Turtle()
t.color("blue")
t.pensize(3)#宽度
#3.用海龟作图
t.forward(100)
t.right(60)
t.pensize(5)
t.backward(150)
t.left(90)
t.color("brown")
t.forward(150)
#4.结束作图
t.hideturtle()#隐藏海龟,可选
turtle.done()
解决问题的典型策略:分而治之
将问题分为若干更小规模的部分
通过解决每一个小规模部分问题,并将结果汇总得到原问题的解
分治策略和递归算法有着天然的联系
每次都试图解决问题的尽量大的一部分
对应到兑换硬币的问题,就是每次以最多数量的最大面值硬币来迅速减少找零面值
贪心策略适用于“局部最优等同于总体最优”的问题求解。
即第一步分解的问题可解决的方法尽量接近总体目标,不存在回溯的问题。
首先确定基本结束条件,兑换硬币这个问题最简单直接的情况就是,需要兑换找零,其面值正好等于某种硬币
其次减小问题的规模,我们对每种硬币尝试一次
对递归解法进行改进的关键在于消除重复计算:可以用一个表将计算过的中间结果保存起来,在计算之前查表看看是否已经计算过
这个算法的中间结果就是部分找零的最优解,在递归调用过程中已经得到的最优解被记录下来
在递归调用前,先查找表中是否已有部分找零的最优解
如果有,直接返回最优解而不进行递归调用
如果没有,则进行递归调用
这种改进叫做记忆化或者函数值存储技术
可用来解决递归重复计算的问题
递归与动态规划不同点:
递归+函数值缓存技术:要什么就算什么,从n(最后,即最大规模)开始,递归调用,所以缓存中的函数值什么时候被算出来未知
动态规划:直接找到最简单的情况,从最简单的情况向目标迭代。
使用动态规划解决问题的要求:大规模问题的解包含了其部分问题的解
背包问题和单词最短编辑距离,如果使用递归来求解,就使用了分治策略;如果使用动态规划则不属于。
列表适用于密集数据集;字典适用于稀疏数据集;集合中的数据项无次序关系,其数据项需要去重复。
记忆化递归求解效率一般高于动态规划,但是递归主要问题是递归会使用系统调用栈,受系统资源影响较大
可迭代对象是可以对包含数据项逐个枚举的对象
集合是“简版”字典,只有key没有value的字典,都是通过散列表来实现
变量、函数命名:必要的注释(关键点、函数参数返回值)
代码格式(PEP8自动格式化)
尽量不用全局变量;
不依赖于某些特定缺省值;
不硬编码某些特定位置、特定值;
一些变量用符号代替,并集中放在文件头部
不要import *
用类的接口方法不是类变量
0-1背包问题的复杂度O(nW)是个多项式时间复杂度
但是在图灵机等价的计算模型下
背包问题的规模取决于最大重量W的二进制位数logW
当logW增加1,计算时间就是原来的2倍,这是指数增长(2**logW)
背包问题是个NP问题,目前尚未找到真正的多项式时间复杂度问题
另一个具有伪多项式时间复杂度算法的NP问题是判断素数
其输入规模为数N的二进制位数logN
当logN增加1,计算时间就是原来的2倍
实际的计算机整数是固定长度,已经预留了至少32bits二进制
当logW增加1,计算时间就是原来的2倍,这是指数增长(2**logW)
背包问题是个NP问题,目前尚未找到真正的多项式时间复杂度问题
另一个具有伪多项式时间复杂度算法的NP问题是判断素数
其输入规模为数N的二进制位数logN
当logN增加1,计算时间就是原来的2倍
实际的计算机整数是固定长度,已经预留了至少32bits二进制