参考自 MOOC数据结构与算法Python版

目录

  • 一、什么是递归Recursion
  • 1. 初识递归
    • 1.1 数列求和
    • 1.2 递归“三定律”
  • 2. 递归的应用
    • 2.1 任意进制转换
    • 2.2 递归可视化:分形树
      • 2.2.1 Python的海龟作图系统turtle module
    • 2.3 找零兑换问题的递归解法

一、什么是递归Recursion

递归是一种解决问题的方法,它将问题分解为规模更小的相同问题,在算法流程中调用自身

1. 初识递归

1.1 数列求和

问题:
给定一个不定长列表, 返回所有数的和。需要一个循环和一个累加变量来迭代求和。
举个例子:
求全括号表达式的和:
total=(1+(3+(5+(7+9))))total =(1+(3+(5+(7+9))))total=(1+(3+(5+(7+9))))
最内层的括号(7+9), 这是无需循环即可计算的, 实际上整个求和的过程是这样:
total=(1+(3+(5+16)))total = (1+(3+(5+16)))total=(1+(3+(5+16)))
total=(1+(3+21))total = (1+(3+21))total=(1+(3+21))
total=(1+24)total = (1+24)total=(1+24)
total=25total =25total=25

  • 观察上述过程中所包含的重复模式, 可以把求和问题归纳成这样:
    数列的和=“首个数”+“余下数列”的和数列的和=“首个数”+“余下数列”的和数列的和=“首个数”+“余下数列”的和
  • 如果数列包含的数少到只有1个的话, 它的和就是这个数了-- 这是规模小到可以做最简单的处理
    程序如下:
def listsum(numList):if len(numList) == 1:return numList[0]else:return numList[0] + listsum(numList[1:])
print(listsum([1,3,4,2,7]))

1.2 递归“三定律”

  1. 递归算法必须有一个基本结束条件(最小规模问题的直接解决)
  2. 递归算法必须能改变状态向基本结束条件演进(减小问题规模)
  3. 递归算法必须调用自身(解决减小了规模的相同问题)

2. 递归的应用

2.1 任意进制转换

  • 我们用最熟悉的十进制分析下这个问题
  • 我们用整数除, 和求余数两个计算来将整数一步步拆开
    – 除以“进制基base”(// base)
    – 对“进制基”求余数(% base)
  • 问题就分解为:
    – 余数总小于“进制基base”,是“基本结束条件”,可直接进行查表转换
    – 整数商成为“更小规模”问题,通过递归调用自身解决
    代码如下:
def toStr(n,base):convertString = "0123456789ABCDEF"if n<base:return convertString[n]else:return toStr(n//base,base) + convertString[n%base]
print (toStr(1453,16))

Python中的递归深度限制

  • 在Python内置的sys模块可以获取和调整最大递归深度
import sys
print(sys.getrecursionlimit())   #1000
sys.setrecursionlimit(3000)
print(sys.getrecursionlimit())   #3000

推荐两部关于闭环递归的电影: 《predestination》–前目的地,《Triangle》–恐怖邮轮

2.2 递归可视化:分形树

下面我们通过递归作图来展现递归调用的视觉影像。

2.2.1 Python的海龟作图系统turtle module
  • Python内置,随时可用,以LOGO语言的创意为基础

  • 其意象为模拟海龟在沙滩上爬行而留下的足迹
    – 爬行: forward(n); backward(n)
    – 转向: left(a); right(a)
    – 抬笔放笔: penup(); pendown()
    – 笔属性: pensize(s); pencolor©
    PS:用这个画图,系统容易崩

  • 画一个五角星:

import turtle
t = turtle.Turtle()
t.pencolor('red')
t.pensize(3)
for i in range(5): t.forward(100)t.right(144)
t.hideturtle()  #隐藏画笔的turtle形状
turtle.done()

  • 一个递归作图的例子:螺旋
import turtle
t = turtle.Turtle()
def drawSpiral(t, lineLen):if lineLen>0:t.forward(lineLen)t.right(90)drawSpiral(t,lineLen-5)drawSpiral(t,100)
turtle.done()

2.3 找零兑换问题的递归解法

问题: 假设你为一家自动售货机厂家编程序,自动售货机要每次找给顾客最少数量硬币
解决方案:

  1. 肯定能找到最优解的方法 – 贪心策略
    (1). 确定基本结束条件
    需要兑换的找零,其面值正好等于某种硬币
    (2). 减少问题的规模,对每种硬币尝试1次, 例如美元硬币体系:

       找零减去1分(penny)后,求兑换硬币最少数量(递归调用自身);找零减去5分(nikel)后,求兑换硬币最少数量找零减去10分(dime)后,求兑换硬币最少数量找零减去25分(quarter)后,求兑换硬币最少数量上述4项中选择最小的一个。
    

    numCoins=min{1+numCoins(originalamout−1)1+numCoins(originalamout−5)1+numCoins(originalamout−10)1+numCoins(originalamout−25)numCoins=min\left\{ \begin{matrix} \begin{matrix} \begin{matrix} 1+numCoins(originalamout-1) \\ 1+numCoins(originalamout-5) \\ \end{matrix} \\ 1+numCoins(originalamout-10) \\ \end{matrix} \\ 1+numCoins(originalamout-25) \\ \end{matrix} \right.numCoins=min⎩⎪⎪⎨⎪⎪⎧​1+numCoins(originalamout−1)1+numCoins(originalamout−5)​1+numCoins(originalamout−10)​1+numCoins(originalamout−25)​
    [注]:1表示其面值正好等于某种硬币,因此只需要1个硬币

    (3). 递归解法代码:

## 虽然能解决问题,但极其低效
def recMC(coinValueList, change):minCoins = changeif change in coinValueList:return 1  #最小规模,直接返回else:for i in [c for c in coinValueList if c <= change]:numCoins = 1 + recMC(coinValueList, change-i) #调用自身:每次减去一种硬币面值挑选最小数量if numCoins < minCoins:minCoins = numCoins return minCoins
print (recMC([1, 5, 10, 25], 63))
  1. 递归算法改进
    (1). 消除重复计算
    可以用一个表将计算结果保存起来
    (2). 算法的中间结果是部分找零的最优解
    在递归调用之前,先查找表中是否有部分找零的最优解
    如果有,直接返回最优解
    如果没有,进行递归调用
    (3). 改进算法代码:
def recDC(coinValueList, change, knownResults):minCoins = changeif change in coinValueList:knownResults[change] = 1return 1  #最小规模,直接返回elif knownResults[change] > 0:return knownResults[change]  #查表成功,直接用最优解else:for i in [c for c in coinValueList if c <= change]:#调用自身:每次减去一种硬币面值挑选最小数量numCoins = 1 + recDC(coinValueList, change-i, knownResults) if numCoins < minCoins:minCoins = numCoinsknownResults[change] = minCoins #找到最优解,记录在表中          return minCoins
print (recDC([1, 5, 10, 25], 63, [0]*64))
  1. 动态规划解法 – 非递归函数
    (1). 动态规划算法采用了一种更有条理的方式来得到问题的解。
    (2). 从最简单的“一分钱找零”的最优解开始,逐步递加上去,知道我们需要的找零钱数。
    (3). 问题的最优解包含了更小规模问题的最优解,这是一个最优化问题能够用动态规划策略解决的必要条件。
    (4) 动态规划算法代码
def dpMakeChange(coinValueList, change, minCoins):for cents in range(1, change+1): #从1开始到change逐个计算最少硬币书coinCount = cents#初始化一个最大值#减去每个硬币,向后查最少硬币数,同时记录总的最少数for j in [c for c in coinValueList if c <= cents]:if minCoins[cents - j] + 1 < coinCount:coinCount = minCoins[cents -j] + 1minCoins[cents] = coinCount #得到当前最少硬币数,记录到表中return minCoins[change]
print(dpMakeChange([1, 5, 10, 21, 25], 63, [0]*64))
  1. 动态规划算法扩展
    在生成最优解列表的同时,跟踪记录所选择的那个硬币币值,从而得到最优解硬币组合
def dpMakeChange(coinValueList, change, minCoins,coinsUsed):for cents in range(1, change+1):coinCount = centsnewCoin = 1 #初始化新加硬币for j in [c for c in coinValueList if c <= cents]:if minCoins[cents - j] + 1 < coinCount:coinCount = minCoins[cents -j] + 1newCoin = j #对应最小数量,所减的硬币minCoins[cents] = coinCountcoinsUsed[cents] = newCoin #记录本步骤加的1个硬币return minCoins[change]
def printCoins(coinsUsed, change):coin = changewhile coin > 0:thisCoin = coinsUsed[coin]print(thisCoin)coin = coin - thisCoin
amnt = 63
clist = [1, 5, 10, 21, 25]
coinsUsed = [0] * (amnt + 1)
coinsCount= [0] * (amnt + 1)
print("Making change for ", amnt, "requires")
print(dpMakeChange(clist, amnt, coinsCount,coinsUsed), "coins")
print("They are:")
printCoins(coinsUsed, amnt)
print("Th used list is as follows:")
print(coinsUsed)

数据结构与算法(python)递归:找零问题相关推荐

  1. Python数据结构20:动态规划:找零兑换问题的动态规划解法并显示使用的硬币组合

    在我们使用递归算法时,可能会出现规模庞大的重复计算,用一个中间表记录每个计算过的最优解法,就可以避免大量的重复计算.中间结果记录可以很好解决找零兑换问题.实际上,这种方法还不能称为动态规划,而是叫做& ...

  2. 数据结构与算法 python版 之 递归三定律

    #数据结构与算法 python版 之 谢尔宾斯基三角形 , 树叉 1.为了向阿西莫夫的"机器人三定律"直径,递归算法也总结出"三定律" 1递归算法必须有一个基本 ...

  3. 《数据结构与算法 Python语言描述》 读书笔记

    已经发布博客 <数据结构与算法 Python语言描述> 读书笔记 第二章 抽象数据类型和Python类 2.1 抽象数据类型abstract data type:ADT 2.1.1 使用编 ...

  4. 数据结构与算法python版

    数据结构与算法 1 递归 1.1 递归条件 1.2 汉诺塔 2 查找 2.1 顺序查找 2.2 二分查找 3 列表排序 3.1 冒泡排序 3.2 选择排序 3.3 插入排序 3.4 快速排序 3.5 ...

  5. 数据结构python课后答案_数据结构与算法:Python语言描述 1~5章课后习题

    数据结构与算法:Python语言描述 1~5章课后习题 发布时间:2018-07-19 20:42, 浏览次数:1885 , 标签: Python MarkDown语法写的,不知道为啥上传到CSDN不 ...

  6. 《数据结构与算法 Python语言实现》书评与学习心得

    做为Python小白,本人几个月前读完了Mark Lutz的1400页巨著<Learning Python>(太TM啰嗦了,读过的请举手),本打算继续学习下一步<Programmin ...

  7. 数据结构和算法(十)递归-迷宫游戏

    1. 数据结构和算法(十)递归-迷宫游戏 1.1 迷宫游戏   今天做一个简单的迷宫游戏,用二维数实现地图,让程序自动寻路的小游戏. 1.2 简单的迷宫 简单的迷宫 用二维数实现地图,找路策略:[右- ...

  8. 数据结构与算法python版 MOOC 第九周

    九.树及算法-上 本系列博客基于" (北京大学)数据结构与算法python版"慕课,课程在中国大学慕课和bilibili上均可找到. 1. 内容 树结构的相关术语 树的表示方法:嵌 ...

  9. mooc数据结构与算法python版第十一周作业_中国大学 MOOC_数据结构与算法Python版_2020最新答案学习指南...

    中国大学 MOOC_数据结构与算法Python版_2020最新答案学习指南 更多相关问题 [判断题]实际集成运放的上限截止频率为无穷大 [多选题]现代城市的发展凸现出与以往不同的动力机制包括 教师在引 ...

  10. 数据结构与算法之递归题目

    数据结构与算法之递归题目 目录 求n!的结果 汉若塔问题 打印字符串的全部子序列,包括空字符串 打印一个字符串的全部排序 1. 求n!的结果 public static long getFactori ...

最新文章

  1. 妙用Java 8中的 Function接口 消灭if...else(非常新颖的写法)
  2. 草根seo站长利用网站赚钱的方法
  3. C++ Primer 5th笔记(chap 17 标准库特殊设施)正则表达式类和输入序列类型
  4. mysql导入sql文件
  5. python中collections模块_Python的collections模块
  6. loadrunner提高篇 - 关联技术的经典使用
  7. php留言板系统制作,php制作留言板讲解
  8. 【STM32 基础实验蜂鸣器发声】
  9. css美化button
  10. Matlab:数组索引
  11. 手机淘宝app、xsign签名算法
  12. Qt实用技巧:自定义窗口标题栏
  13. 【EasyExcel导入、导出(百万数据量测试)粘贴即用】
  14. 【bzoj1818】[Cqoi2010]内部白点
  15. 软件测试如何分类?又有哪些类别?
  16. 检查并杀死mysql锁死的进程
  17. 兔将十年大作《赤狐书生》特效解析:青蛙精篇
  18. SDL游戏开发之一-SDL的简介
  19. 2021年4月Bmob无法访问Bmob云服务器
  20. 【Linux集群教程】12 集群安全防御 - 安全防御概述和Linux防火墙

热门文章

  1. 彩虹文字--RainbowText
  2. python智能家居教程_泡泡云服务器移植python3.6 home-assistant(智能家居平台)
  3. java 圈复杂度_详解圈复杂度
  4. 【云原生-白皮书】简章1:为什么我们需要云原生架构?
  5. CCS报错errors encountered during linking以及unresolved symbols remain
  6. 如何在Linux下方便的启动Oracle
  7. py语法基础010_字符串操作
  8. 4K画质修复神器,模糊照片秒变高清
  9. 【答辩问题】计算机专业本科毕业设计答辩详细指导
  10. 李明顺:互联网金融最需要正能量