动态规划(Dynamic programming,简称DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。
动态规划类的题目在leetcode中是一大类,可以使用DP求解的问题一般有如下几个特点:
1) 计数
1.1)有多少种方式跳到右侧,多少种方式走到右下角
1.2)有多少种方法选出K个数使得和是Sum
2)求最大值和最小值
2.1)从左上角走到右下角路径的最大数字和
2.2)最长上升子序列
2.3)背包能装的最大价值
2.4) 小偷能偷的最大价值等等
3)求存在性
3.1)取石子游戏,先手是否必胜
3.2)能不能选出K个数使得和是Sum
3.3)能否跳到最后一块石头上
等等...
下面将动态规划问题分为坐标型、序列型、划分型、背包型,分别进行典型题目的梳理。
- 坐标型
https://leetcode.com/problems/jump-game/
该题可以归结为一维坐标类型的动态规划,相对而言是比较简单的一种。一般解决问题的思路为:
- 确定状态
- 将问题化解为最后一步
- 推导出最后一步需要的步骤,分解为子问题
- 转移方程
根据分解的子问题,找到状态转移方程
3. 确定初始值和边界情况。
初始f[0], f[1]等于多少,循环的开始和结束,返回值是哪个?
4. 确定计算顺序
确定从f[0]开始还是从f[1],或者从最后的f[n]开始?
这一题我们按照上面的步骤进行思考。从最后一步,如果能跳到最后一个位置,即n – 1, 我们考虑这一步是从哪里(i)调过来。i < n – 1。这需要两个条件满足,即可以跳到第i个石头,而且跳跃距离不超过它和最后一个元素的距离 n – 1 – i <= nums[i]。
那么我们可以得到状态转移方程:
初始条件很简单,f[0] = true,从1开始计算,到最后一个元素。代码如下: