动态规划算法
一般决策类问题(0-1背包问题)或者含有大量重叠的子问题(爬楼梯)会考虑用动态规划解题,通过寻找最优子结构来求解大问题的最终答案
1. 解题套路
1.1 明确dp
数组含义
动态规划问题通过定义dp
数组来记录解题过程中的最优子结构
,dp
数组的维度是由解题的需要来确定的,比如爬楼梯的问题,每次爬1层或爬2层,是一个一维的问题,定义dp[i]
为爬上i
阶楼梯的有dp[i]
种方法;又比如在m x n
的网格上向下走一步和向右走一步到达终点的方式,这是一个典型的dp[i][j]
二维数组的问题,定义dp[i][j]
表示为达到坐标为(i,j)
的点,一共有dp[i][j]
种方式
1.2 写出状态转移方程
状态转移方程就是要找出,爬1级,爬2级;向左走,向下走;对字符串的操作是增,删,改的不同策略和dp[i][j]
的等式关系:
对于爬楼梯,需要找出一共有多少种策略:
|
|
对于不同路径问题,也是需要找到总共的路径数:
|
|
对于求编辑距离问题,需要找的是最小值,在前一操作的基础上,再进行一次操作:
|
|
1.3 找出初始值
这里的初始值是在状态转移方程失效的情况下,dp
数组对应的值,通常情况下是在dp
数组的前面几个值,例如dp[0]
,dp[0][1...n]
,dp[1...n][0]
情况下,dp
数组的值
2 题目实战
2.1 简单一维数组dp问题
题目 : 70 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
|
|
dp三板斧
-
明确
dp
数组含义1
dp[i]的含义就是爬上一个i阶的台阶共有dp[i]种方法
-
状态转移方程
1 2 3 4 5
这里一共有两种爬楼梯的方式,爬1个台阶,或者爬2个台阶,我们已经定义了爬上一个i阶的台阶共有dp[i]种方法,那么当最后一次爬上了1个台阶或爬上了两个台阶,在这之前一共有多少种方式呢: 爬一个台阶:dp[i-1] 爬两个台阶:dp[i-2] 所以 dp[i][j] = dp[i-1] + dp[i-2]
-
初始值
1 2 3
当n == 1时,只能有爬1级楼梯这1种方式 当n == 2时,只有爬2次1级楼梯和爬1次2级楼梯这两种方式 只有当n > 3时,才存在爬1级楼梯和爬2级楼梯的不同组合方式
代码
|
|
2.2 中等难度二维数组dp问题
题目 :62. 不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
示例 1:
|
|
dp 三板斧
dp
数组含义
|
|
- 状态转移方程
|
|
- 初始情况
|
|
代码
|
|
2.3 较难二维数组dp,状态超过3种情况
题目: 72.编辑距离
给你两个单词 word1
和word2
,请你计算出将 word1
转换成 word2
所使用的最少操作数(编辑距离) 。
你可以对一个单词进行如下三种操作:
插入一个字符 删除一个字符 替换一个字符
示例 1:
|
|
dp
三板斧
-
dp数组含义
1
dp[i][j]表示word1的前i个字母和word2的前j个字母之间的编辑距离
-
状态转移方程
1 2 3 4 5 6 7 8
增删改对应3种状态 D[i][j-1] 为 A 的前 i 个字符和 B 的前 j - 1 个字符编辑距离的子问题。即对于 B 的第 j 个字符,我们在 A 的末尾添加了一个相同的字符,那么 D[i][j] 最小可以为 D[i][j-1] + 1; D[i-1][j] 为 A 的前 i - 1 个字符和 B 的前 j 个字符编辑距离的子问题。即对于 A 的第 i 个字符,我们在 B 的末尾添加了一个相同的字符,那么 D[i][j] 最小可以为 D[i-1][j] + 1; D[i-1][j-1] 为 A 前 i - 1 个字符和 B 的前 j - 1 个字符编辑距离的子问题。即对于 B 的第 j 个字符,我们修改 A 的第 i 个字符使它们相同,那么 D[i][j] 最小可以为 D[i-1][j-1] + 1。特别地,如果 A 的第 i 个字符和 B 的第 j 个字符原本就相同,那么我们实际上不需要进行修改操作。在这种情况下,D[i][j] 最小可以为 D[i-1][j-1]。 dp[i][j] = min(dp[i-1][j-1],min(dp[i][j-1],dp[i-1][j])) + 1
图解
绿色:增 红色:删 黄色:改
-
确定初始情况
1 2
当i == 0 时,表示将一个空串变为word2,我们只要依次插入就行了,所以 dp[0][i] = dp[0][i-1] + 1 当j == 0 时,表示word1变为一个空串,我们只要依次删除就行了,所以 dp[i][0] = dp[i-1][0] + 1
代码
|
|