算法学习——动态规划1
众所周知,在面试中最难,也是大公司最容易考的就是动态规划,所以今天打算开撕动态规划,之前只是对于单个的题目知道解法,不过时间一久就忘记了,今天开始要彻底的理解方法论再到实践,希望老天保佑能够一周搞定!
一.通过一个小例子了解方法论:
一个例子,如上图:
求从起点到终点的最短路径:
这是一道最基本的动态规划问题,如果不使用动态规划可以使用穷举进行求解,路径大概存在2的k次方。利用动态规划求解主要步骤:
1. 找出规划的初始状态:对此,找出第一个子问题的解从而可以在后面的内容中利用该解来作为后面状态的条件,在这一问题中初始状态就是最邻重点的c点到终点的最短距离。
2. 规划决策路线,这一问题的决策路线是将边界从起点不断的向终点进行移动,如下图。有些问题是从起始状态向终点逐渐向最终状态进行推进,知道最后到达最终
状态。
2. 转化方程:对于动态规划其求解在于,子子问题->子问题->问题,利用上一状态来求解下一状态,找出前后的关系,最终求解。如下图,该题中的关系非常简单,就是利用前一子问题的解加上当前结点到下一个的最短路线。
3.收敛条件:找出最终状态的终点在哪
4.适用的优化原则:一个最优决策序列的任何子序列本身一定是相对于子序列本身的初始和结束状态的最优决策序列。
二. 动态规划的设计要素
在第一部分中写了一些关于求解动态规划的个人看法,下面几条是教学视频中总结并列举动态规划基本步骤:
1.问题建模,优化的目标函数是什么?约束条件是什么?
2.划分子问题(边界)
3.子问题和父问题的依赖关系(递推方程)
4.满足优化,判断是否满足优化原则
5.最小子结构,最小函数值是什么,初值是什么?
以上五点可以总结为动态规划的方法论,以后刷题中并非所有问题都可以根据以上五点进行教科书式的照搬,但是系统的分析动态规划问题,以上五点是对于分析动态规划问题非常重要的步骤,尤其对于初学者来讲。如下图,利用一个矩阵链相乘的例子,来利用动态规划的方法来求解此问题。
1.问题建模,优化的目标函数是什么?约束条件是什么?
此问题的目标函数在于找出矩阵相乘找出最小的结果,即:
min = P[0,i]*P[i+1,n]可以得到最小值。
2.划分子问题(边界)
子问题的边界,首先将初始划分边界的i值从0-n全部遍历一遍,找出相乘得到的最小值,此时的i则是划分出来的子区间,再对于[0,i]与[i+1,n]中继续按照之前遍历进行划分,依次类推,直到不可分。找到局部的最小值,从而得到最优解。
3.子问题和父问题的依赖关系(递推方程)
递推方程,如下图:
所谓递推方程最重要的就是一层一层的向最终结果递进,在每一层中遍历所有的元素,找到这一层子问题最优的解,并运用在下一层中。直到达到最终状态,这就是所谓的记忆化编程。
4.满足优化,判断是否满足优化原则
子问题优化,整体问题也会随之优化,找出的子问题的解也是子过程的最优解。
5.最小子结构,最小函数值是什么,初值是什么?
最小子结构就是第一次对于整个输入的数组进行遍历找出,分隔的最小的点i,这就是初值。
三.动态规划的递归实现:
1.部分伪码
以上为前一题矩阵链相乘的递归实现的伪码:
1.利用m来记录最终结果的大小q
2.s来记录划分的位置k
3-7. 遍历i到k和k+1到j并通过递归调用进行计算,并且不断刷新k和q的值
8.返回最终结果
2. 有关复杂度:
3.产生子问题的划分过程:
递归实现的主要的局限在于同一个子问题会被多次实现,所以其时间复杂度会比较高,解决这一问题可以通过记录子问题结果的方式来实现,下面动态规划的迭代实现。
四.动态规划的迭代实现:
动态规划的迭代实现是后面解题的最常用的方式,比起递归的方法,迭代的时间复杂度会小很多,但是需要一个数据结构作为备忘录对每次子问题的结果进行记录,这样可以避免多次重复计算:
1.迭代计算的关键:
1.每个子问题只计算一次
2.从最小的子问题算起,考虑计算顺序,保证后面的计算过程中前面计算的结果可以用到。
3. 用数据结构作为备忘录进行存储
4.设置标记函数,用标记函数对每一步的解法实施标记,最后得到最终的解法。
2. 对于子问题的划分可以递归扩大其长度:
如图,子问题长度从2到8,对于每一个长度的划分可以列出所有可能的解
r=2时 存在7种
r=3时 存在6种
r=4时 存在5种
r=5时 存在4钟
以此类推,由此可在每次划定r时找出最小值
3.相关伪码
1.初始化最初子结构
2.从2到n遍历r可能的链长
3-4.在链长固定的情况找出划分的左右边界i和j,i与j的距离始终为r
5. 在备忘录中通过前一子结果得出当前结果,一次划分的初始结果
6. 记录划分位置k
7. 通过点k再在i和j之间进行划分
8-11.找出最优的子划分的位置k以及值t,第八行为状态转移方程
4.时间复杂度:
5.备忘录m,标记表格n
五.总结
今天认真系统的学习了一下动态规划,发现以前的学习和刷题都是像蜻蜓点水一样,浪费了很多时间,并且不得要领。目前距离完全理解动态规划还有很长的学习距离,但是打开的系统学习的第一部,真的很重要,下面几条是我结合教学视频上的几点进行总结:
1. 最重要的就是对于动态规划状态的划分,最终状态是什么,从什么状态可以到达最终状态,又从初始状态下怎么达到那一状态。换言之,就是对于子问题的划分,将问题求解转化为多步运算或者多步判断的过程.
2.确定该问题能否使用动态规划,通过极小值或者极大值作为判断
3.解题的关键在于定义转化方程,例如在最小矩阵链中,一个问题结果可以在若干个子选项中选出一个最小的方案,加上当前数值放在备忘录中
4.利用数据结构建立备忘录,常见数组,矩阵,有时也可能有哈希表的存在
5.有时还需要建立状态转移矩阵,因为可能不仅仅是数值,而且还存在数值相对应的状态,例如索引和其他属性需要记录。
好长,,,,,第一次写的这么认真,过段时间复习希望可能看懂,如果一年前开始接触算法题能这样做的话,我可能心在也有工作了,,,,心塞