动态规划总结
动态规划
利用历史记录,避免重复计算
- 定义数组元素含义,用来保存历史数组。
- 找出元素之间的关系(类似归纳法)
- 找出初始值
例子
一维DP
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
定义$dp[i]$为青蛙跳到地$i$级台阶的总跳法。
青蛙跳到第$i$个台阶有两种跳法,分别是从$i-1$和$i - 2$阶跳过来,所以有$dp[i]=dp[i-1]+dp[i-2]$
下标不允许为负,如果$dp[2]=dp[1]+dp[0]$,第0个台阶就为0种跳法,$dp[1]=1$,此时$dp[2]=1$但是如果有两阶应该有两种跳法才对,因此$dp[2]=2$也是初始值。
代码如下:
1 | int f(int n) { |
二维DP-1
一个机器人位于一个 m x n 网格的左上角
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角
问总共有多少条不同的路径?
定义$dp[i][j]$为机器人走到$(i,j)$这个位置时,一共有$dp[i][j]$种路径
机器人要达到$dp[i][j]$有两种走法,分别是从$(i, j-1)$和$(i-1,j)$走到$(i,j)$,所有就有$dp[i][j]=dp[i-1][j] + dp[i][j-1]$
保证数组下标不为负数,所以$i$和$j$不为0,所以将最上面一侧和最左面一侧置1
代码实现:
1 | int uniquePaths(int m, int n) { |
二维DP-2
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
1 | 举例: |
从左上角走到$(i, j)$这个位置时,最小的路径和是$dp[i][j]$
要达到$dp[i][j]$有两种走法,分别是从$(i, j-1)$和$(i-1,j)$走到$(i,j)$,但是需要找最小路径和,所有就有$dp[i][j]=min(dp[i-1][j] , dp[i][j-1]) + arr[i][j]$
保证数组下标不为负数,所以$i$和$j$不为0,所以将最上面一侧和最左面一侧先计算出来
代码实现:
1 | int minimumPathSum(vector<vector<int>> arr) { |
编辑距离
给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
1 | 示例 1: |
当字符串 word1 的长度为 i,字符串 word2 的长度为 j 时,将 word1 转化为 word2 所使用的最少操作次数为$dp[i][j]$
如果$word1[i]$与$word2[j]$相等,这个时候不需要进行任何操作,显然有$dp[i] [j] = dp[i-1] [j-1]$。
如果$word1[i]$与$word2[j]$不相等,这个时候我们就必须进行调整,而调整的操作有 3 种,我们要选择一种。三种操作对应的关系试如下:
如果把字符$word1[i]$替换成与 word2[j] 相等,则有$dp[i][j] = dp[i-1][j-1] + 1$;
如果在字符串$word1$末尾插入一个与 word2[j] 相等的字符,则有 $dp[i][j] = dp[i][j-1] + 1$;
如果把字符$word1[i]$删除,则有$dp[i][j] = dp[i-1][j] + 1$;
那么我们应该选择一种操作,使得$dp[i][j]$的值最小,显然有
$$dp[i][j] = min(dp[i-1][j-1],dp[i][j-1],dp[[i-1][j]]) + 1$$
先计算出所有的$dp[0][0….n]$和所有的$dp[0….m][0]$,当有一个字符串的长度为 0 时,转化为另外一个字符串,那就只能一直进行插入或者删除操作了
代码实现:
1 | int minDistance(string word1, string word2) { |





