动态规划专题(I)

来源:互联网 发布:图解网络硬件 kindle 编辑:程序博客网 时间:2024/04/30 21:07

动态规划与分治法类似,都是通过组合子问题的解来求解原问题。分治方法将问题划分为互不相交的子问题,递归的求解子问题,再将它们组合起来,求出原问题的解。与之相反,动态规划应用于子问题重叠的情况,不同的子问题具有公共的子子问题。这个时候,分治算法会做许多不必要的工作,它会反复的求解那些公共子子问题,而动态规划则对每个子问题只求解一次。举例来说,在之前的文章《排序算法总结》中,我们介绍了一些采用分治策略的算法,比如归并算法,快速排序算法等,它们会把数组分为两个部分,两个部分是不相交的,然后分别处理每个部分,这里就不存在重叠子问题。但是对于爬楼梯问题,如果采用递归解法,那么当我们算第4层的时候,会计算第3层与第2层,当我们计算第3层时,会计算第2层与第1层,可见第2层被重复计算了,这种情况下效率会很低,动态规划则能很好的处理这种问题。

设计一个动态规划的步骤:

1.刻画一个最优解的结构特征

2. 递归的定义最优解的值

3.计算最优解的值

4.利用计算信息构造出一个最优解

下面我们具体看一下。

刻画一个最优解的结构特征是第一步,也是最难的一步了,动态规划威力巨大,可不见得人人都能想到,这一点还要“靠感觉”,但是也有一些小的技巧帮助我们启发思维。首先动态规划有一维的,也有二维的,还有三维的(四维的很少见),这跟坐标系一样不同的维度,如果只涉及一个点集就是一维的,如果涉及到两个点集元素之间的关系则是二维的。。。,在解决动态规划问题时也有类似的规律。如果我们的问题只涉及一个对象,比如前面提到的爬楼梯问题,那么它很有可能是一维的,如果涉及到两个对象,比如最长公共子序列问题,那么它一般是二维的,这时它的结构就是int[][] dp = new int[len1][len2]的形式。当然,这也不能太绝对,leetcode上有一道题目(后面会介绍),涉及到三个对象,但是结果却是用二维dp解决的,这种情况一般是因为三者之间有固定的关系,可以使我们消掉一维,前面提到的这道题就是这种情况。还需要说明一点,我们上句话中提到的”对象“要正确理解,比如并不一定两个字符串才算两个对象,一个字符串也可能是两个”对象“,这主要是由我们研究的问题的结构决定的,比如找一个字符串中的回文子串问题。另外,我们发现动态规划与高中学习的数学归纳法有些类似,这也启发我们在解决这类问题时可以从一个小规模的问题开始尝试。我还常用的另一种方法就是假设,比如通过前面介绍的,我认为这是一个二维动态规划问题,那么我就会假设dp[len1][len2]就是我最终要求的解,然后从这个假设开始倒着推,看看能不能有什么新的发现。

在解决了上面的问题之后,动态规划还有一点可能会遇到的困难就是解的构造。比较复杂的就是通过dfs进行最终解的构造了,这种情况多加练习就可以了。

接下来一篇博客会通过具体的题目来加深dp的理解和应用。



参考

《算法导论》


0 0
原创粉丝点击