#198 打劫家舍(浅谈动态规划)
Origin:https://leetcode-cn.com/problems/house-robber/
题目本身不难,就是一个动态规划的问题。在这里浅谈一下动态规划的精髓思想,适用范围。
动态规划的定义大家在网上随便都可以搜到。但是我们要怎么理解和应用动态规划。即我们遇到问题的时候,要怎么才能“想到”动态规划呢?
- 可以将一个问题,拆分成几个子问题。
- 这不废话吗?任何问题都可以拆分成很多个子问题,那凭什么动态规划那么牛逼呢?
- 解决这几个子问题,即可得到最终问题的解。
- 那这是怎么实现的呢?
- 例如,假设我要求f(n)的最大值,只需要知道f(n-1)和f(n-2)的最大值。
- 于是,上面简简单单一句话,透露了动态规划的很多信息。
- f(n)只和f(n-1), f(n-2)的值有关系。
- 我们只关心数值本身,不需要详细的知道f(n)是怎么来的,简化思维过程。
- 于是,上面简简单单一句话,透露了动态规划的很多信息。
- 可以将一个问题,拆分成几个子问题。
所以,由此可见,动态规划解题的性质即:把求解f(n)转换为求解与其相关的f(p)
那么问题又来了,我如何判断一个问题能不能用动态规划解决呢?下面介绍两个概念
无后效性
定义:如果给定某一阶段的状态,则在这一阶段以后过程的发展不受这阶段以前各段状态的影响。
例如,求斐波那契数列第N项。我们都知道递归公式 f(n) = f(n-1) + f(n-2),那么我们求f(n)的所有所需条件就是知道f(n-1)和f(n-2),我们不需要知道。
过去的内容不会影响将来的内容,这就是无后效性的本质。
最优子结构
这里用背包问题来讲解
背包问题:有一个背包,他的容量为C(Capacity)。现在有n中不同的物品,编号为0…n-1,其中每一件物品的重量为w(i),价值为v(i)。问可以向这个背包中盛放哪些物品,使得在不超过背包容量C的基础上,物品的总价值最大。
动态规划是解决背包问题最常用的方法,把问题的转态描述为:F(n,C)考虑将n个物品放进容量为C的背包,使得价值最大。
而对于F(i,c),有两种情况,将第i个物品加入和直接忽略第i个物品
F(i,C) = max{F(i-1, C), v(i) + F(i-1, C-w(i))}
前者即为忽略第i个物品,后者即添加第i个物品。
那么,这和最优子结构有什么关系呢?注意我们的定义,F(n,C)考虑将n个物品放进容量为C的背包,使得价值最大。不难发现,F(n,C)的定义已经是最大价值了,那么已经是当前小问题的最优解了。最终问题的最优解可以由小问题的最优解得到,这个性质叫做最优子结构。
只要一个问题有 无后效性 和 最优子结构,就可以用动态规划解决。
那最后,我知道要用动态规划了,我要怎么设计呢?
- 记住三个词语
- 目标
- 状态
- 转移
- 目标即我要干嘛?我要干嘛,在背包问题中,我要使一定容量的包装最值钱的东西。设这样的函数为 F(i, c)。
- 状态即怎么描述当前的局面。对于任意一次拿物品,当前的背包还剩k空间,我们目标都是求得F(i, k)。
- 转移是紧跟着状态的,找出F(i, k)与哪些局面有关系,记为p,写出状态转移方程,通过F(p)来求解 F(i, k)。
转自知乎@阮行止
设计DP算法,往往可以遵循DP三连:
我是谁? ——设计状态,表示局面
我从哪里来?
我要到哪里去? ——设计转移设计状态是DP的基础。接下来的设计转移,有两种方式:一种是考虑我从哪里来;另一种是考虑我到哪里去,这常见于求出f(x)之后,更新能从x走到的一些解。这种DP也是不少的,我们以后会遇到。
- 记住三个词语