【零基础】学python数据结构与算法笔记14-动态规划

文章目录

  • 前言
  • 88.动态规划介绍
  • 89.钢条切割问题
  • 90.钢条切割问题:自顶向下实现
  • 91.钢条切割问题:自底向上实现
  • 92.钢条切割问题:重构解
  • 93.最长公共子序列
  • 最长公共子序列:实现
  • 总结


前言

学习python数据结构与算法,学习常用的算法,
b站学习链接

88.动态规划介绍

动态规划在基因测序、基因比对、hmm 有应用场景。

从斐波那契数列看动态规划
在这里插入图片描述
练习: 使用递归和非递归的方法来求解斐波那契数列。

【零基础】学python数据结构与算法笔记14-动态规划_第1张图片
这种非递归求斐波那契数,可以看成是一个动态规划思想,每次都会把重复子问题的答案存起来。

89.钢条切割问题

【零基础】学python数据结构与算法笔记14-动态规划_第2张图片
【零基础】学python数据结构与算法笔记14-动态规划_第3张图片
长度为n的一共有n-1口可以切,每一口可以选择切或者不切,所以有2^n-1种不同的方法。

【零基础】学python数据结构与算法笔记14-动态规划_第4张图片
r[i]那行是长度为i时,最多买的钱。可以这样考虑,在长度为2时,可以选择切成1和1 或者不切,不切最大利润是5,切了后最大利润是2,把最大利润存到r[2]下,当r[3]时,可以不切或者切成1和2(不考虑切成1、1、1,因为在r[2]中已经考虑过1和1 的利润没2大),选择最大的8存放在r[3]中,按照这样的思想,比方说看r[9],看不切或1和8或2和7或3和6或4和5,选择最大的放到r[9],
先看1和8,1+22
2和7,5+18
3和6,8+17
4和5,10+13
于是我们可以推出递推式,不切和切一刀之后最大值就是利润最大。此时从左边往右边切和从右边往左切是一样的,但我们还是考虑了切成5和4,切成6和3的情况。
【零基础】学python数据结构与算法笔记14-动态规划_第5张图片
我们可以将求解规模为n的原问题划分成规模更小的子问题:完成一次切割后,可以将产生的两端钢条看成两个独立的钢条切割问题,

【零基础】学python数据结构与算法笔记14-动态规划_第6张图片
这就叫最优子结构,把9的最大=3最大+6最大。

此时可以得出以上的递推式,不过还可以再进行简化,以上是不切和切一次的不同位置来构成的递推式。
【零基础】学python数据结构与算法笔记14-动态规划_第7张图片
这样还是切9, 左边一部分是不切的,所以价值是原来不切的价值
1和8,1+20
2和7,5+18
3和6,8+17
4和5,9+13
5和4,10+10
6和3,17+8
7和2,17+5
8和1,20+1
25还是最大,为什么可以这样做呢?因为现在最大是3和6 实则是3和6,但假设如果最大是23 那就是2和2和2和3,2没切,后面的7切成了三段,或者假设说是4和5,4没切,5切成2和3,那么就是说,这样左边没切,右边切,所有的情况还是都能列举,之前的方法有重复了,所以可以这样简化。

90.钢条切割问题:自顶向下实现

对照上面的公式写出以下两种实现,第二种简化的方法,少了一次递归,时间上少了很多。
【零基础】学python数据结构与算法笔记14-动态规划_第8张图片
将p改成p = [0,1,5,8,9,10,17,17,20,24,30,31,33,35,36,40,41,42,45,46,50],长度改大,计算最大的时间也变慢了。

【零基础】学python数据结构与算法笔记14-动态规划_第9张图片
因为递归算法由于重复求解相同子问题,效率极低,随着长度越大,求解速度会变慢
在这里插入图片描述
因为这是用了自顶向下递归实现,为何自顶向下递归的效率会这么差?
时间复杂度为O(2^n),如果n越大,就会造成指数爆炸。
求f(4),会重复求许多相同的问题。
【零基础】学python数据结构与算法笔记14-动态规划_第10张图片

动态规划的思想:每个问题只求解一次,保存求解结果
之后需要此问题时,只需要查找并保存结果。

91.钢条切割问题:自底向上实现

动态规划就是自底向上实现,每次都把最好的存起来,调用时直接取出来,不用再算。
按照第二种简化的方法写。
【零基础】学python数据结构与算法笔记14-动态规划_第11张图片
时间上比递归的方法快很多,时间复杂度为O(n^2)
【零基础】学python数据结构与算法笔记14-动态规划_第12张图片

92.钢条切割问题:重构解

如何修改动态规划算法,使其不仅输出最优解,还输出最优切割方案?
对每个问题,保存切割一次时左切切下的长度,s[i]为保存的当前最优利润时,左切下的长度
【零基础】学python数据结构与算法笔记14-动态规划_第13张图片
max()的话就不知道里面左边不切割的长度是多少,所以要换成以下写法
【零基础】学python数据结构与算法笔记14-动态规划_第14张图片
实际上这样把每次切出来的长度列出来,有个专有的名词叫路径带回
在这里插入图片描述
什么问题可以用动态规划方法?涉及到最大,最小,最优时
【零基础】学python数据结构与算法笔记14-动态规划_第15张图片
实际上,贪心算法是动态规划一个特例,贪心能解动态也能解,贪心不能解,动态也能解。
可以先从递归的思想想问题,如果递归能解就意味着动态规划能解。

93.最长公共子序列

【零基础】学python数据结构与算法笔记14-动态规划_第16张图片
首先要找到递推式或者说是最优子结构。
我们发现这样一个规律,如果两个字符串的最后一个字符不相等,比如说“ABCBDAB”和“BDCABA”这两个字符串找最长公共子序列。我们先看最后一个字符,不一样,那么我们可以等同于“ABCBDAB”和“BDCAB”中找最长公共子序列,或者“ABCBDA”和“BDCABA”中找,两者中哪个最长就是最长的公共子序列。如果最后一个字符一样,比如“ABCBDA”和“BDCABA”,那么最长的公共子序列就等于“ABCBD”和“BDCAB”的最长公共子序列 +1(因为最后一个字符相等)。
就得出如下定理:
【零基础】学python数据结构与算法笔记14-动态规划_第17张图片
安照这个图得出,空字符时都为0,如果末尾字符相等,那就取上面格子和下面格子的最大值,如果不相等,就取左上角一个格子的值+1。(从左上角过来的值代表匹配)
【零基础】学python数据结构与算法笔记14-动态规划_第18张图片

最长公共子序列:实现

首先求最长公共子序列的长度
【零基础】学python数据结构与算法笔记14-动态规划_第19张图片
再利用回溯法得出,这个最长的子序列的字符是多少
【零基础】学python数据结构与算法笔记14-动态规划_第20张图片
这种做法只能求得一个,如果 elif c[i-1][j] > c[i][j-1]: 改成 >= 则答案是BCBA,这两个都是最长公共子序列,所以都是对的。
存的路径如下。
【零基础】学python数据结构与算法笔记14-动态规划_第21张图片

总结

学习了动态规划算法。

文章目录

  • 前言
  • 88.动态规划介绍
  • 89.钢条切割问题
  • 90.钢条切割问题:自顶向下实现
  • 91.钢条切割问题:自底向上实现
  • 92.钢条切割问题:重构解
  • 93.最长公共子序列
  • 最长公共子序列:实现
  • 总结


你可能感兴趣的:(python,动态规划,算法)