问题介绍
大致做法:大问题分解为小问题,存储子问题的解避免重复计算。
最优子结构:原问题的最优解是从子问题的最优解构造来的
重叠子问题:相同的问题会被多次计算
无后效性:问题的当前状态的最优解不受其未来状态的影响
存储子问题的解:通常使用表格(数组或者哈希表)来存储子问题的解
计算顺序:子问题间存在依赖性,要保证计算一个子问题前,其依赖的所有子问题已经解决
代码实际概念
状态:子问题的定义,通常用一个或者多个变量来表示
状态转移方程:描述如何从已知子问题的解来计算另一个子问题的解的公式
边界条件:子问题的基本情况,常用于递归算法的基准情况
动态规划表:通常是一个表格,用来存储子问题的解,避免重复计算
何时应用动态规划
- 问题是否可以被分解为子问题? 这意味着问题可以递归地解决。
- 子问题之间是否存在重叠? 如果是,每个子问题是否在整个过程中被多次计算?
- 问题是否具有最优子结构? 即你可以通过组合子问题的最优解来得到原问题的最优解。
经典问题
- 背包问题:求解如何在一个限定容量的背包中放入不同物品使得价值最大化。
- 最长公共子序列问题:找到两个字符串的最长公共子序列。
- 矩阵路径问题:求解从矩阵的一个角到另一个角的最短路径、最大路径等。
- 股票买卖问题:给定一段时间的股票价格,求最大利润。
- 编辑距离问题:最少的操作次数将一个字符串转换为另一个字符串。
问题通解
第一步、描述决策、定义状态、建立dp表、
确定dp表的下标含义和大小
第二步、思考子问题条件(利用反推)推导状态转移方程、
子问题可以简单粗暴由原问题更改为中间值i
思考子问题由什么条件来,进而推导状态转移方程
第三步、确定边界条件(初始条件)
第四步、确定状态转移顺序——
备忘录法,自顶向下,递归;
dp数组法,自底向上,递归消除;
是否可能覆盖需要的数据
第五步、举例推导dp数组