动态规划是一个经典而实用的算法,常常在面试题中出现。html
以最著名的刷题网站leetcode为例,目前有147道动态规划算法题,占比约 13% 。前端
其重要性可见一斑~git
这篇文章就来详细分析一下动态规划相关知识点。github
综合维基百科和《算法导论》的说法,能使用动态规划解决的问题必须包含下面两个要素:面试
重叠子问题很好理解,递归就是解决重叠子问题的一种方式。 简单理解就是父问题和子问题处理方式一致,可是规模不一样。 下面来重点须要分析最优优子结构。算法
问题的最优解包含其子问题的最优解。数组
或者说就是经过子问题的解能够推导出父问题的解。记住是子问题的解而不是子问题自己。缓存
如何理解?举个例子:bash
给定一个整数数列 [12, 18, 21, 60],求下面两个问题前端工程师
对于第一个问题就是具备最优子结构,由于将问题(数组)拆分后求解的结果能够用于问题自己的解。
子数组的偶数个数 + 当前数是否为偶数 ? 1 : 0 = 数组的偶数个数
第二个问题就不具备最优子结构,将问题(数组)拆分后求得的解不能直接用于问题自己的解。
子数组的最小公倍数 + 数组某个元素 =/=> 当前数组最小公倍数
第一个问题咱们不须要关心子数组的内容,只须要关心子数组的结果便可,而第二个问题咱们须要知道子数组的组成。
固然有专业术语能够来表述这种情形,叫作“无后效性”。
《算法导论》中给出的通用模式(套路)以下:
虽然我对描述语言进行了精简,可是看起来仍是有些啰嗦。再用一句话来归纳就是“不断缩减问题的规模”,记住是缩减规模不是缩减条件。
以爬楼梯问题为例进行说明:
题目:一我的上楼梯,楼梯有n阶台阶,一次能够上1阶或2阶。问有多少种上楼梯的方式。
对于这个问题使用动态规划来考虑,分解的子问题应该是:
爬 n - 1 阶楼梯有多少种方式
爬 n - 2 阶楼梯有多少种方式
复制代码
而缩减条件的方式是(这是错误的思路)
爬 n 阶楼梯每次只爬1阶有多少种方式
爬 n 阶楼梯每次只爬2阶有多少种方式
复制代码
理论上来讲,大多数问题均可以经过(暴力)枚举来解决。可是一般枚举是下册,由于效率过低,没法在有限的时间或空间内获得结果。
因此咱们若是将动态规划算法和枚举相比,那么它至少具备两个优点。
借用知乎答主阮行止的一个例子进行说明。
题目:一个国家的钞票面额分别是1元、5元、11元,如何用最少的钞票凑出15元?
先看解答过程:
用dp(n)
函数表示凑出n元时须要的钞票数量。 那么n = 15时考虑可能由 n=10 时加一张5元,n=14 时加一张1元,n=4 时加一张11元。用公式表述以下:
dp(15) = min{dp(10) + 1, dp(14) + 1, dp(4) + 1}
加上已知条件:dp(11) = dp(5) = dp(1) = 1,整个推导公式以下图:
{% asset_img dp15.jpg %}
而后再结合起来理解动态规划算法的优点。
某公司出售一段长度为99米可切割的钢条,已知钢条的价格为Pi(i=1,2,3...),钢条长度均为整数。长度价格关系以下:
长度i 1 2 3 4 5 6 7 8 9 10
价格Pi 1 5 8 5 10 17 17 20 24 30
复制代码
求收益最大的切割方案。
参考:
原文连接:tech.gtxlab.com/dp.html 做者信息:朱德龙,人和将来高级前端工程师。