动态规划的本质
常用的五大算法,包含 动态规划、分治法、贪心求解法、回朔法、分支限界法。
动态规划(Dynamic Programming),与其说是一种算法,不如说是一种解决问题的思路。 :peach:
Dynamic Programming is a methed for solving a complex problem by breaking it down into a collection of simpler subproblems.
上述引自维基百科,也就是说动态规划就是将一个复杂的问题分解成若干简单的问题集的一种方法。
那么怎么分解问题就成了动态规划的本质。
而分解问题,依靠的就是 问题的状态 和 状态之间的转移。
- 如何定义一个状态
我们需要找到一个问题在某一个状态的 最优解。 :strawberry:
举个例子:
最长递增子序列(LIS)
给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)
例如:给定一个长度为6的数组A{5, 6, 7, 1, 2, 8}
则其最长的单调递增子序列为{5,6,7,8},长度为4
由此我们定义一个状态,当以第i个数组元素结尾的最长递增子序列dp(i)。
整个数组的LIS就是dp(1)…dp(n)的最大值。
由此我们就定义好了一个问题的状态,下面我们就看看不同状态之间的转移。
- 如何找到状态的转移
首先,我们需要找到状态的 边界值。 :watermelon:
根据上述LIS的问题,边界值为当i=1时,最长递增子序列为1。
然后,我们需要找到状态之间的 关系。 :banana:
dp(i) = max(1,dp(j)+1...) (0<=j<i) 当array[j]<array[i]
解释一下,在保证第i项比第j项大的情况下,要取之前所有项的最长递增子序列加1的最大值。
这里可以看出,这里的状态转移方程,就是定义了问题和子问题之间的关系。
可以看出,状态转移方程就是带有条件的递推式。
动态规划经典练习
这里罗列了6道比较经典的动态规划练习。 :corn:
1 | 复制代码/** |
请先根据动态规划的本质,定义出 状态 和 状态之间的关系,然后再进行代码编写。
如果你已经完成了练习,这里有上述问题的答案,戳这里。
本文转载自: 掘金