持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
64. 最小路径和
思路
(动态规划) O(m*n)
状态表示: f[i,j]表示从(0,0)走到(i,j)的最小路径和。那么,f[n-1][m-1]就表示从网格左上角到网格右下角的最小路径和,即为答案。
状态转移:
由于限制了只会向下走或者向右走,因此到达(i,j)有两条路径
- 从上方转移过来,
f[i][j] = f[i-1][j] + grid[i][j] - 从左方转移过来,
f[i][j] = f[i][j-1] + grid[i][j]
因此,状态计算方程为: f[i][j] = max(f[i - 1][j], f[i][j - 1]) + grid[i][j], 从向右和向下两条路径中选择路径之和最小的转移过来,再加上grid[i][j]的值。
初始化条件: f[0][0] = grid[0][0], 其余都初始化为正无穷。
时间复杂度分析: O(m*n),其中 m和 n分别是网格的行数和列数 。
c++代码
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int n = grid.size(), m = grid[0].size();
vector<vector<int>> f(n + 1, vector<int>(m + 1, INT_MAX));
f[0][0] = grid[0][0];
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++){
if(!i && !j) continue;
if(i) f[i][j] = min(f[i - 1][j] + grid[i][j], f[i][j]);
if(j) f[i][j] = min(f[i][j - 1] + grid[i][j], f[i][j]);
}
return f[n - 1][m - 1];
}
};
70. 爬楼梯
思路
(递推) O(n)
分析题目可以发现:
- 上 1 阶台阶:有1种方式。
- 上 2 阶台阶:有1+1和2两种方式。
- 上 3 阶台阶:到达第3阶的方法总数就是到第1阶和第2阶的方法数之和。
- 上 n 阶台阶,到达第n阶的方法总数就是到第 (n-1) 阶和第 (n-2) 阶的方法数之和。
因此,定义数组 f[i] 表示上i 级台阶的方案数,则枚举最后一步是上1级台阶,还是上2级台阶,所以有: f[i] = f[i−1]+f[i−2]。
时间复杂度分析: 递推状态数O(n),转移时间复杂度是 O(1),所以总时间复杂度是 O(n)。
c++代码
class Solution {
public:
int climbStairs(int n) {
if(n <= 2) return n;
vector<int>f(n + 1);
f[1] = 1;
f[2] = 2;
for(int i = 3; i <= n; i++){
f[i] = f[i - 1] + f[i - 2];
}
return f[n];
}
};
72. 编辑距离
思路
(动态规划) O(n * m)
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
状态表示: f[i][j] 表示将 word1 的前 i 个字符变成 word2 的前 j 个字符需要进行的最少操作次数。
状态计算:
如何计算f[i][j]?考虑word1的第i个字符与word2的第j个字符(下标从1开始),分为两种情况:
-
1、
word1[i] == word2[j],则f[i][j] == f[i - 1][j - 1]; -
2、
word1[i] != word2[j],我们有三种选择,替换、删除、插入:- 替换: 替换
word1的第i个字符或者替换word2的第j个字符,则f[i][j] == f[i - 1][j - 1] + 1; - 删除: 删除
word1的第i个字符或者删除word2的第j个字符,则f[i][j] = min(f[i - 1][j], f[i][j - 1]) + 1; - 插入: 在
word2[j]后面添加word1[i]或者在word1[i]后添加word2[j],则f[i][j] = min(f[i - 1][j], f[i][j - 1]) + 1;
- 替换: 替换
初始化:
for(int i = 0; i <= n; i++) f[i][0] = i; //将长度为i的word1变成长度为0的word2需要进行最少i次删除操作
for(int i = 0; i <= m; i++) f[0][i] = i; //将长度为i的word2变成长度为0的word1需要进行最少i次添加操作
时间复杂度分析: 状态数为O(n * m),状态计算为O(1),因此总的时间复杂度为O(n * m)。
c++代码
class Solution {
public:
int minDistance(string word1, string word2) {
int n = word1.size(), m = word2.size();
word1 = ' ' + word1;
word2 = ' ' + word2;
vector<vector<int>>f(n + 1, vector<int>(m + 1));
for(int i = 0; i <= n; i++) f[i][0] = i; //i次删除
for(int i = 0; i <= m; i++) f[0][i] = i; //i次添加 word1 -> word2
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
f[i][j] = min(f[i - 1][j], f[i][j - 1]) + 1; //添加或者删除
int t = word1[i] != word2[j];
f[i][j] = min(f[i][j], f[i - 1][j - 1] + t); //替换
}
return f[n][m];
}
};