动态规划
数字三角形
如上图所示,请找出一条自顶向下路径,使得该路径上所有数字的和最大。
- 如何定义状态?第i行第j个数
- 如何进行搜索?DFS枚举所有路径即可(回溯法)
- 时间复杂度?若共有n层,时间复杂度O(2^n)
是否可以减少不必要的搜索(规避不必要的状态转移)了呢?
- 注意第3行第2个数
- 若价值函数定义恰当,则只需搜过一次即可:记忆化搜索
动态规划Dynamic programming,DP
在搜索过程中,对于已经搜索过、且价值函数不会再度更新(或变优)的状态,则可以通过记忆化的方式,规避重复搜索。
因此,才有动态规划算法适用问题所具备的必要条件:
- 最优子结构:最优解可以由子问题的最优解(或部分状态的最优价值函数)构造得出
- 重叠子问题:一些子问题(或状态)在搜索中会重复遇到
- 无后效性:子问题最优解一旦确定就不会再被更新
- 该性质可以直接否定某些问题使用动态规划的可行性。其实,此性质暗示了动态规划可解问题的状态空间一般都是有向无环图
动态规划的宏观理解
本质就是状态空间中的一种“聪明的”搜索策略,因此
- 依然需要恰当准确的状态空间建模
- 重点在于状态的价值函数的设计(通常为优化目标函数)
- 同时,状态转移过程中的价值函数更新方式也很关键
关键点
动态规划算法解决问题的难点不仅是能否准确地、用尽可能少的状态变量(或称为维度)对问题建模,还要设计合理的价值函数(甚至赋予特殊意义),并准确地给出价值函数在状态转移过程中的更新方式。
鉴于以上,才可以总结出动态规划算法设计的三个关键环节:
- 定义状态和价值函数(建模)
- 确定初始状态和对应价值(边界)
- 确定状态转移中的价值更新方式(状态转移方程)
动态规划两种实现
记忆化搜索Memorization
自顶向下(top-down)的实现(DP的本质:暴力搜索优化)
- 状态:递归函数的参数形式
- 状态转移:函数调用,通过实际传入参数
- 价值函数:函数的返回值,须记录(数组或字典)
打表法Tabulation
自底向上(bottom-up)的实现(动态规划的常见方案)
- 状态:数组的下标
- 状态转移:数组元素间的递推关系
- 价值函数:数组的值
所以如何游刃有余地掌握动态规划算法?积累模型
类型Ⅰ:一维递推问题(求和形式)
爬楼梯
一个由n级台阶的楼梯,每步可以迈1、2、3级,问爬完这段楼梯有几种不同的方式?
- 如何定义状态和价值函数?f(i)表示走到第i级台阶的种类数
- 状态转移方程?
- 边界与答案?边界,答案为
- 时间复杂度?O(n)
优化方式
矩阵快速幂优化:,O(log n)
类型Ⅱ:一维递推问题(最值形式)
-
最长上升子序列Longest increasing sequence,LIS
给一个数组,请找出这个数组中的一个最长的单调递增子序列(可以不连续)
- 如何定义状态和价值函数?f(i)为第i个数作为结尾的最长上升子序列的长度
- 状态转移方程?
- 边界与答案?,答案为
- 时间复杂度?O(n^2)
优化方式
- 单调队列/栈优化 Monotonic queue/stack:
- 斜率优化 Convex hull trick:
类型Ⅲ:二维问题----区间问题
最长回文子序列Longest Palindromic Subsequence
回文指形如:“ABBA”,“CDC”等正反一样的序列,给出任意序列,计算最长回文子序列长度。(如“GOODGAME”的答案“GOOG”)
- 如何定义状态和价值函数?表示区间i,j之间的最长回文子序列长度
- 状态转移方程?
- 边界与答案?,答案
- 时间复杂度?O(n^2)
回文子序列的个数Couting Palindromic Subsequences
求字符串中回文子序列的个数。(如CDC的回文子序列包括C,D,C,CC,CDC,共5个,位置不同的相同序列需要重复计数)
- 如何定义状态和价值函数?表示区间i,j之间的最长回文子序列个数
- 状态转移方程?
- 边界与答案?,答案
- 时间复杂度?O(n^2)
最优矩阵链乘法
n个矩阵连续相乘,第i个矩阵的维度为,问如何通过加括号的方式最快完成矩阵乘法?
- 如何定义状态和价值函数?为i,j间的最快方案
- 状态转移方程?
- 边界与答案?,答案
- 时间复杂度?O(n^3)
优化方式
四边形不等式优化Knuth optimization
区间最值查询Range Minimum/Maximum Query,RMQ
给出长度为n的数组和m次询问,每次询问要求l,r区间内最值
- 如何定义状态和价值函数?为以i为起点,长度为2^j的区间最值(倍增思想)
- 状态转移方程?
- 边界与答案?,令,答案为
- 时间复杂度?O(n logn + m)
类型Ⅳ:二维问题----序列间比较问题
编辑距离Edit distance
给出字符串A和B,对A进行三种操作:插入、删除或替换一个字符,问由A修改为B最少要几步?
- 如何定义状态和价值函数?为使A长度为的前缀与B长度为的前缀通过编辑实现匹配的最少次数
- 状态转移方程?
- 边界与答案?,答案
- 时间复杂度?O(n^2)
类型Ⅴ:树与图上的问题
快乐聚会
某公司中有明确的上下属关系,可以用有根树表示。现举办聚会,每个人都有一个快乐指数,但是如果一个人的上属参加了聚会,那么此人就不会参加,求聚会最大快乐指数和?
- 如何定义状态函数和价值函数?表示员工x参加/不参加聚会时其与其下属的最大快乐指数之和
- 状态转移方程?
- 边界与答案?,答案为
- 时间复杂度?O(n)