动态规划题目特点:
1,计数
—机器人有多少种方式走到右下角
—有多少种方法选出k个数使得和是sum
2,求最大最小值
—从左上角走到右下角路径的最大数字和
—最长上升子序列问题
3,求存在性
—取石子游戏,先手是否必胜
—能不能选出k个数使得和是sum
最值型动态规划例题
例题:有2,5,7三种面值的硬币,如何以最少的硬币拼成27(LeetCode上第322题!)
-
动态规划组成部分之一:确定状态
确定状态需要有两个意识,最优策略的最后一步和子问题。在本例题中可以理解为拼成27的最后一枚硬币是Ak,故最优解法是k-1枚硬币拼成了27-Ak,这样的思考方式就兼顾了最后一步和子问题,也就确定了状态。状态f(X) = 由最少用多少枚硬币拼出X,其中f(X)是数组!
子问题:f(X) = f(X-2) +1
f(X) = f(X-5) +1
f(X) = f(X-7) +1 ,求以上三个式子的min
题目分析到这里,其实可以用递归的思想进行求解,但递归解法涉及的时间复杂度太大(许多情况需要重复计算),所以接着往下分析。
-
动态规划组成部分之二:转移方程,根据子问题定义直接得到
对于任意X,f[X] = min{f(X-2) +1,f(X) = f(X-5) +1,f(X) = f(X-7) +1},这里再次强调,f[X]是数组!
-
动态规划组成部分之三:初始条件与边界情况,细心、考虑周全
在往下分析的过程中会遇到两个要考虑的地方,当X-2,X-5,X-7小于0怎么办以及什么时候停下来?我们可以事先定义当拼不出X时,f[X] = 正无穷,这是边界情况,初始条件f[0] = 0
-
动态规划组成部分之四:计算顺序,利用之前的计算结果
一般情况下是按照从小到大的顺序计算,先计算初始条件f[0],再计算f[1],f[2],.....,当我们计算到f[X]时,f(X-2),f(X-5), f(X-7)都已经计算过了,至此问题得解。
代码:
计数型动态规划例题
例题:Unique Path,机器人从左上角走到右下角多少种走法(LeetCode上第62题!)
-
确定状态:f[i][j]为机器人有多少种方法走到(i,j)
-
转移方程:f[i][j] = f[i - 1][j] + f[i][j - 1]
-
初始条件:f[0][0] = 1,机器人只有一种方式走到左上角(注意不能是0)
-
边界情况:i = 0或j = 0,此时只能有一种方法走过来,f[i][j] = 1,这步很重要!
-
计算顺序:对于二维问题,先一行行的计算,再计算列(从左到右),最后返回值为f[i][j]
-
代码如下:
存在性动态规划例题
例题:Jump Game (最好的解法是贪心算法)
-
确定状态:设f[j]表示青蛙能不能跳到石头j
-
转移方程:f[j] = OR 0<=i<j) (f[i] AND i + a[i] >= j)
-
初始条件:f[0] = true
-
边界情况:无
-
计算顺序:计算f[0],f[1],f[2],...,答案是f[n-1],第一块石头是f[0]
-
代码如下:
-
Jump Game2,求出最少要跳几次才能到达最后一块石头,代码如下:
下面是一种高效的解法: