【数据结构与算法Python版学习笔记】递归(Recursion)——优化问题与策略
分治策略:解决问题的典型策略,分而治之
- 将问题分为若干更小规模的部分
- 通过解决每一个小规模部分问题,并将结果汇总得到原问题的解
递归算法与分治策略
- 递归三定律
- 体现了分支策略
- 应用相当广泛
- 排序
- 查找
- 遍历
- 求值等
优化问题
- 计算机科学中许多算法都是为了找到某些问题的最优解
- 两点之间最短路径
- 能最好匹配一系列点的直线
- 满足一定条件的最小集合
经典案例:找零兑换
贪心策略
- 兑换最少个数的硬币
- 贪心策略及失效
- 63=252+101+1*3
- 63=21*3
递归解法
- 步骤
- 确定基本结束条件
需要兑换的找零,面值正好等于某种硬币 - 减少问题规模
对每种硬币尝试一次
- 确定基本结束条件

- 低效代码
import time
def recMC(coinValueList, change):
minCoins = change
if 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
if __name__ == "__main__":
print(time.clock())
print(recMC([1, 5, 10, 25], 63))
print(time.clock())
memoization 记忆化/函数值缓存
优化
- 消除重复计算
用一个表将计算过的中间结果保存起来,在计算之前查表看看是否已经计算过- 有,直接返回最优解
- 无,进行递归调用
import time
def recMC(coinValueList, change, knowResults):
minCoins = change
if change in coinValueList:
knowResults[change] = 1
return 1
elif knowResults[change] > 0:
return knowResults[change]
else:
for i in [c for c in coinValueList if c <= change]:
numCoins = 1+recMC(coinValueList, change-i, knowResults)
if numCoins < minCoins:
minCoins = numCoins
knowResults[change] = minCoins
return minCoins if __name__ == "__main__":
meno = [0]*64
print(time.clock())
print(recMC([1, 5, 10, 25], 63, meno))
print(time.clock())
print(meno) >>>
2e-07
6
0.0061154
[0, 1, 0, 0, 0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 3, 4, 5, 6]
- 消除重复计算
动态规划解法
步骤
- 从最简单的“1分钱找零”的最优解开始,逐步狄加上去,直到我们需要的找零钱数
- 在找零递加的过程中,一直加到求解找零钱数,自然得到最优解
- 递加的过程能保持最优解的关键是,其依赖于更少钱数最优解的简单计算,而更少钱数的最优解已经得到了
- 问题的最优解包含了更小规模子问题的最优解。
这是一个最优化问题能够用动态规划策略解决的必要条件
思想
- 从最简单的情况开始到达所需找零的循环
- 每一步都依靠以前的最优解来得到本步骤的最优解,直到得到答案
代码实现
def dpMakeChange(coinValueList, change, minCoins, coinUsed):
# 1.从一分钱到change逐个计算最少硬币数
for cents in range(1, change+1):
coinCounts = cents
newCoin = 1
# 2.减去每个硬币,向后查最少硬币数,同时记录总的最少数
for j in [c for c in coinValueList if c <= cents]:
if minCoins[cents-j]+1 < coinCounts:
coinCounts = minCoins[cents-j]+1
newCoin = j
# 3.得到当前最少硬币数,记录到表中
minCoins[cents] = coinCounts
coinUsed[cents] = newCoin
return minCoins[change]
def printCoins(coinUsed, change):
coin = change
while coin > 0:
thisCoin = coinUsed[coin]
print(thisCoin)
coin = coin-thisCoin
if __name__ == "__main__":
amnt=63
clist=[1, 5, 10, 21, 25]
coinUsed=[0]*(amnt+1)
coinCount=[0]*(amnt+1)
print("Making change for",amnt,"require",dpMakeChange(clist, amnt, coinCount,coinUsed),"coins")
print("They are:")
printCoins(coinUsed, amnt)
print("The used list is as follows:")
print(coinUsed)
>>>
Making change for 63 require 3 coins
They are:
21
21
21
The used list is as follows:
[0, 1, 1, 1, 1, 5, 1, 1, 1, 1, 10, 1, 1, 1, 1, 5, 1, 1, 1, 1, 10, 21, 1, 1, 1, 25, 1, 1, 1, 1, 5, 10, 1, 1, 1, 10, 1, 1, 1, 1, 5, 10, 21, 1, 1, 10, 21, 1, 1, 1, 25, 1, 10, 1, 1, 5, 10, 1, 1, 1, 10, 1, 10, 21]
博物馆大盗问题

- 动态规范代码
def calcTreasure1():
"""动态规划宝物价值最大化"""
# 宝物价值和重量
tr = [
None,
{'w': 2, 'v': 3},
{'w': 3, 'v': 4},
{'w': 4, 'v': 8},
{'w': 5, 'v': 8},
{'w': 9, 'v': 10}
]
# 达到最大承重
max_w = 20
# 初始化二位表格m[(i,w)]
# 表示前i个宝物中,最大重量w的组合,所得到的最大价值
# 当i什么都不取,或w上限为0,价值均为0
m = {(i, w): 0 for i in range(len(tr))
for w in range(max_w+1)}
#逐个填写二维表格
for i in range(1,len(tr)):
for w in range(1,max_w+1):
if tr[i]['w']>w:
m[(i,w)]=m[(i-1,w)]
else:
m[(i,w)]=max(
m[(i-1,w)],
(m[(i-1,w-tr[i]['w'])]+tr[i]['v'])
)
# 输出结果
print(m)
print(m[(len(tr)-1,max_w)])
if __name__ == "__main__":
calcTreasure1()
- 递归解法
# 宝物价值和重量
tr = {(2, 3), (3, 4), (4, 8), (5, 8), (9, 10)}
# 达到最大承重
max_w = 20
# 初始化二位表格m
# key是(宝物组合,最大重量),values是最大重量
m = {}
def thief(tr, w):
if tr == set() or w == 0:
m[tuple(tr), w] = 0
return 0
elif (tuple(tr), w) in m:
return m[tuple(tr), w]
else:
vmax = 0
for t in tr:
if t[0] <= w:
# 逐个从集合中去掉某个宝物,递归调用
# 选出所有价值中的最大值
v = thief(tr-{t}, w-t[0])+t[1]
vmax = max(vmax, v)
m[tuple(tr), w] = vmax
#print("%2d ---- %2d " % (vmax,w),tr)
return vmax
print(thief(tr, max_w))
【数据结构与算法Python版学习笔记】递归(Recursion)——优化问题与策略的更多相关文章
- 【数据结构与算法Python版学习笔记】引言
学习来源 北京大学-数据结构与算法Python版 目标 了解计算机科学.程序设计和问题解决的基本概念 计算机科学是对问题本身.问题的解决.以及问题求解过程中得出的解决方案的研究.面对一 个特定问题,计 ...
- 【数据结构与算法Python版学习笔记】目录索引
引言 算法分析 基本数据结构 概览 栈 stack 队列 Queue 双端队列 Deque 列表 List,链表实现 递归(Recursion) 定义及应用:分形树.谢尔宾斯基三角.汉诺塔.迷宫 优化 ...
- 【数据结构与算法Python版学习笔记】递归(Recursion)——定义及应用:分形树、谢尔宾斯基三角、汉诺塔、迷宫
定义 递归是一种解决问题的方法,它把一个问题分解为越来越小的子问题,直到问题的规模小到可以被很简单直接解决. 通常为了达到分解问题的效果,递归过程中要引入一个调用自身的函数. 举例 数列求和 def ...
- 【数据结构与算法Python版学习笔记】查找与排序——散列、散列函数、区块链
散列 Hasing 前言 如果数据项之间是按照大小排好序的话,就可以利用二分查找来降低算法复杂度. 现在我们进一步来构造一个新的数据结构, 能使得查找算法的复杂度降到O(1), 这种概念称为" ...
- 【数据结构与算法Python版学习笔记】树——相关术语、定义、实现方法
概念 一种基本的"非线性"数据结构--树 根 枝 叶 广泛应用于计算机科学的多个领域 操作系统 图形学 数据库 计算机网络 特征 第一个属性是层次性,即树是按层级构建的,越笼统就越 ...
- 【数据结构与算法Python版学习笔记】算法分析
什么是算法分析 算法是问题解决的通用的分步的指令的聚合 算法分析主要就是从计算资源的消耗的角度来评判和比较算法. 计算资源指标 存储空间或内存 执行时间 影响算法运行时间的其他因素 分为最好.最差和平 ...
- 【数据结构与算法Python版学习笔记】基本数据结构——列表 List,链表实现
无序表链表 定义 一种数据项按照相对位置存放的数据集 抽象数据类型无序列表 UnorderedList 方法 list() 创建一个新的空列表.它不需要参数,而返回一个空列表. add(item) 将 ...
- 【数据结构与算法Python版学习笔记】图——骑士周游问题 深度优先搜索
骑士周游问题 概念 在一个国际象棋棋盘上, 一个棋子"马"(骑士) , 按照"马走日"的规则, 从一个格子出发, 要走遍所有棋盘格恰好一次.把一个这样的走棋序列 ...
- 【数据结构与算法Python版学习笔记】树——利用二叉堆实现优先级队列
概念 队列有一个重要的变体,叫作优先级队列. 和队列一样,优先级队列从头部移除元素,不过元素的逻辑顺序是由优先级决定的. 优先级最高的元素在最前,优先级最低的元素在最后. 实现优先级队列的经典方法是使 ...
随机推荐
- 性能测试必备命令(3)- lscpu
性能测试必备的 Linux 命令系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1819490.html 介绍 显示有关CPU架构的信息 ...
- web安全性测试——XSS跨站攻击
1.跨站攻击含义 XSS:(Cross-site scripting)全称"跨站脚本",是注入攻击的一种.其特点是不对服务器端造成任何伤害,而是通过一些正常的站内交互途径,例如发布 ...
- springcloud3(五) spring cloud gateway动态路由的四类实现方式
写这篇博客主要是为了汇总下动态路由的多种实现方式,没有好坏之分,任何的方案都是依赖业务场景需求的,现在网上实现方式主要有: 基于Nacos, 基于数据库(PosgreSQL/Redis), 基于Mem ...
- IPsec 9个包分析(主模式+快速模式)
第一阶段:ISAKMP协商阶段 1.1 第一包 包1:发起端协商SA,使用的是UDP协议,端口号是500,上层协议是ISAKMP,该协议提供的是一个框架,里面的负载Next payload类似模块,可 ...
- C# Dapper基本三层架构使用 (四、WinForm UI层)
UI层主要功能是显示数据和接受传输用户的数据,可以在为网站的系统运行提供交互式操作界面,表示层的应用方式比较常见,例如Windows窗体和Web页面. 在项目中增加WinForm应用程序,结构如下 添 ...
- elasticsearch入门到放弃之elasticsearch-head
elasticsearch-head可理解为跟DBeaver一样是一个数据可视化工具,但是这个工具并没有理想中那么好用坑也是很多,我已经在我的github上fork了一份修改后的版本:https:// ...
- pyhton锁机制,进程池
第一,进程锁,本来进程是各自的,本不要加锁,但是在屏幕上输出打印时为了防止混乱,在进程模块有一个锁函数,使用如下,需要说明是在py3以上版本没 有出现在过屏幕输出混乱,可以不加,这方法不重要,但是作为 ...
- Jenkins教程(七)实现 GitLab 提交/合并代码触发构建
楔子 最近公司推行统一构建平台(基于 Jenkins + Kubernetes 插件创建 slave),原来部门自建的 Jenkins 不让用了. 迁移上统一构建平台的最大阻力是前端模块发布的问题: ...
- 安卓学习记录(五)——体温表APP.2
一.项目结构 二.源码 1.数据层 db+dao+bean package com.example.tem.db; import android.content.Context; import and ...
- vue报错 Uncaught TypeError: Cannot read property of null
有可能是点击a标签,但是a标签有click事件,未阻止默认事件导致报错,开始都看不出来是什么错误