THU

编程入门 行业动态 更新时间:2024-10-20 00:22:47

<a href=https://www.elefans.com/category/jswz/34/1767179.html style=THU"/>

THU

数据结构,邓俊辉老师
平台——学堂在线 =learn_title

动态规划

动态规划的引入

Make it work, Make it right, Make it fast.
Kent Beck

通过递归给到一个初步的解后,再进行改进

首先,观察实例——斐波那契数列的递归计算
+现象,在43项后结果产生发生延迟,查看任务管理器,发现内存满负荷工作
+问题 代码这么慢,从复杂度的角度到底如何解释?
O(φ^n),斐波那契的递归实例,在时间复杂度上呈指数级别

封底估算

  • φ = 黄金分割比例(长/短)约为1.61803

  • φ^36 = 2^25

  • φ^43 = 2^30 = 10^9 flo = 1sec
    即,普通计算机一秒钟的吞吐量
    更好理解指数,有助于对我们估计计算的延迟

  • 近似式φ^5大致是10,
    那么φ^67次方大致是10^14 flo= 10^5 sec = 1 day

用递归跟踪方法,认识到递归版fib()低效的根源在于,各递归实例均被大量重复调用
改进思维:每个实例只计算一次,改进算法

斐波那契数列的迭代法

改进方法一,是直截了当的(记忆法:memoization)
每次试图生成新的递归实例时,都试图检查一下实例是否之前已经被唤醒,是,则直接取出。即将已计算过实例的结果制表备查

改进方法二,方法更加通用,而且更加自然(动态规划:dynamic programming)
由自顶而下递归,改为自底而上迭代,“每个台阶”上只需要停留一次

+代码

f = 0; g =1; //fib(0), fib(1)while (0 < n--){g = g + f;f = g - f; //感受一下这步的精妙
}
return g;

呈现一种交替的滚动的方式,直到得到最后的解,与n成线性关系,只需要g和f两个存储单元,空间上是常数空间,

实例,最长公共子序列

概念,子序列,邻边彼此不能交叉
最长公共子序列,特殊情况,可能同时有多个公共子序列,这里将模型简化,不考虑特殊情况

+思维方法
按Kent Beck所建议的工作流程,暂时把计算效率放在一边,首先建立一个正确的可行的方案
方案一,递归求解
可能的三种情况:1)至少一个为空集,2)末字符相同,3)末字符不同(对称考虑两种情况,如图解有两种情况,即考虑两个递归实例)原问题的解无非是,两个子问题中的最长者
+问题,效率不高
绘制成表格理解整个计算过程
右下角(红色方块)为原问题的解,同时存在多条通路的情况,如上图

正确性和复杂度分析

  • 单调性,无论如何,每经过一次比对,问题的规模必可减小。
    最好情况(不出现第二种情况)下,只需O(n+m)时间
  • 但在第二种情况,原问题讲分解为两个子问题,更糟糕的是,它们在随后进一步导出的子问题,总而造成整体上大量雷同,与fib实例,完全类似

一个更宏观的角度:

  • 把其中所有的递归实例,按坐标的形式表示为(n,m)或(0,0);
  • 为了计算出算法复杂度的最终结果,先考虑我们唤醒(a, b)递归实例的通路次数
  • 考虑特例(0,0)的情况,若n = m(整个区域为方形),总数大致为O(2^n)

动态规划的策略,“似拙实巧”的方法

让计算的方向“颠倒”过来
逐行逐列进行填写

对于任何一个单元,根据具体情况(减而治之or分而治之)来选择如何处理

具体来看:

  • 分而治之,左上角对应元素+1(如图中a行a列得到数值2)
  • 减而治之,取上方和左侧元素,取最大值(如图t行c列得到数值2)
  • 从行再到列,取法是安全的、准确的

方向为最初向左向上的逆向策略
任何一个子问题都只需要计算一次,颠倒次序以后的迭代式的计算过程,复杂度恰好等于表格的规模O(n*m)

+总结
递归:设计出可行且正确的解
动态规划:消除了重复计算,提高效率改进成了实用的算法,

缓存

缓存作用,拿出来,放到唾手可得的地方去
类比:书架和书包
书包:所有学习工具的子集,不同学期不同天会变化,在局部时间被高效实用

就地循环问题

仅用O(1)辅助空间,将数组A[0,n)中的元素向左循环移动k个单元

统一接口:void shift(intA, int n , int k);
第一种,蛮力版
考虑最基本的动作,移动一位,通过while循环反复移动一位
共迭代k次,O(n
k)

第二种,“占坑”循环的迭代版—— 数论同余——封闭散列的一种状态,迟早会回到原位

  • 但并不保证,所有数都能被检视到 改进
  • 从起始点下一位也做一次同余列的“直奔主题”的就位
  • O(greatest common divisor) = O(GCD(n,k))

另一解法,Reverse


+直观,用坡度代表数组的前后
将区间翻转—— 就地算法(形似彩虹)

复杂度,n/2 * 3(交换三句)*2(总长翻转两次) = 3n

邓俊辉老师看法
该算法给满分——什么原因?

连续储存

  • 联系Cache序列—— 访问时,机器用cache装下最近用的最多的东西
  • 多次使用以后,根据数据cache会用到这个数据或者附近的数据,装到更小的更高速的缓存中去,访问的是item,装进去的是一批数据

  • 白色——外存,内存——绿色(几个数量级的差别)

进一步地,联系缓存机制思考,为什么前面的算法不好? 为什么reverse算法,表面看起来3n,实际快?
—— 访问有规律性,虽也会周期性做一次I/O, 但周期变得更长,负担变得更小,效果反而更快

+本节重点
注意数据访问的姿势,彼此挨着的,走的有“规律”,“仆人”操作系统能更好发挥性能

向量

(a) 接口与实现
如何根据同一的接口,定制一个数据结构?
如何通过更有效的算法,使得对外的接口更高效率地工作?
——> 后续课程

更多推荐

THU

本文发布于:2024-02-24 16:24:43,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1695942.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:THU

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!