1.什么是动态规划?
维基百科:动态规划(Dynamic programming,简称DP)是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。
使用场景:动态规划常常适用于有重叠子问题和最优子结构性质的问题。
dynamic programming is a m·· ethod for solving a complex problem by breaking it down into a collection of simpler subproblems.
简单来说,动态规划其实就是,给定一个问题,我们把它拆成一个个子问题,直到子问题可以直接解决,然后把子问题答案保存起来,以减少重复计算。再根据子问题答案反推,得出原问题解的一种方法。
动态规划最核心的思想,就在于拆分子问题,记住过往,减少重复计算。
一般这些子问题很相似,可以通过函数关系式递推出来。动态规划就致力于解决每个子问题一次,减少重复计算,比如`斐波那契数列`,就可以看做入门级的经典动态规划问题。
2.动态规划3个核心点
- 确定边界--退出条件
- 确定最优子结构--拆分子问题
- 状态转移方程--子问题合并方式,即子问题和原问题关系,将子问题结果合并得出最终答案
对于这个3点,后面会做一一解释,请看我道来。
3.从「钱」讲起
一个算法星球的央行发行了奇葩币,币值分别为1、5、11,要凑够15元最少要几个货币?
它的问题其实是「给定一组面额的硬币,我们用现有的币值凑出n最少需要多少个币」。
我们要凑够这个 n,只要 n 不为0,那么总会有处在最后一个的硬币,这个硬币恰好凑成了 n,比如我们用 {11,1,1,1,1} 来凑15,前面我们拿出 {11,1,1,1},最后我们拿出 {1} 正好凑成 15。
如果用 {5,5,5} 来凑15,最后一个硬币就是5,我们按照这个思路捋一捋,:
- 那么假设最后一个硬币为11的话,那么剩下4,这个时候问题又变成了,我们凑出 n-11 最少需要多少个币,此时n=4,我们只能取出4个面值为1的币
- 如果假设最后一个硬币为 5 的话,这个时候问题又变成了,我们用现有的币值凑出 n-5 最少需要多少个币
大家发现了没有,我们的问题提可以不断被分解为「我们用现有的币值凑出 n 最少需要多少个币」,比如我们用 f(n) 函数代表 「凑出 n 最少需要多少个币」.
把「原有的大问题逐渐分解成类似的但是规模更小的子问题」这就是最优子结构,我们可以通过自底向上的方式递归地从子问题的最优解逐步构造出整个问题的最优解。
这个时候我们分别假设 1、5、11 三种面值的币分别为最后一个硬币的情况:
- 最后一枚硬币的面额为 11: min = f(4) + 1
- 最后一枚硬币的面额为 5: min = f(10) + 1
- 最后一枚硬币的面额为 1: min = f(14) + 1
这个时候大家发现问题所在了吗?最少找零 mi