写在前面
本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更……
专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:
- Tag:介绍本题牵涉到的知识点、数据结构;
- 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
- 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
- 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
- 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。
Tag
【字符串】【动态规划】
题目来源
解题思路
方法一:动态规划
定义状态
定义 dp[i][j]
表示字符串 word1
中前 i
个字符,变换到 word2
中前 j
个字符,需要的最短操作次数。
转移关系
题目中允许增、删和改三种操作,我们认为这三种操作都是对字符串 word1
进行作用:
- 增加一个字符才能使字符串
word1
中前i
个字符变换成word2
中前j
个字符,则有dp[i][j] = dp[i][j-1] + 1
,也就是字符串word1
中前i
个字符和word2
中前j
个字符是一样的,增加一个word[j]
才能让字符串word1
中前i
个字符变和word2
中前j
个字符一样。 - 删除一个字符,有转移关系
dp[i][j] = dp[i-1][j] + 1
。 - 修改一个字符,有转移关系
dp[i][j] = dp[i-1][j-1] + 1
。
以上三种情况是在 word1[i-1] != words[j-1]
时,需要进行变换。如果相等,则 dp[i][j] = dp[i-1][j-1]
。
base case
需要考虑 word1
和 word2
为空字符串的情况,直接见代码。
最后返回
最后返回 dp[m][n]
,
m
m
m 和
n
n
n 分别表示字符串 word1
和 word2
的长度。
代码
class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size();
vector<vector<int>> dp(m+1, vector<int>(n+1));
// 字符串word2为空的base case
for (int i = 0; i <= m; ++i) {
dp[i][0] = i;
}
// 字符串word1为空的base case
for (int j = 0; j <= n; ++j) {
dp[0][j] = j;
}
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (word1[i-1] == word2[j-1]) {
dp[i][j] = dp[i-1][j-1];
}
else {
dp[i][j] = min(dp[i][j-1], min(dp[i-1][j], dp[i-1][j-1])) + 1;
}
}
}
// 最后返回
return dp[m][n];
}
};
复杂度分析
时间复杂度:
O
(
m
n
)
O(mn)
O(mn),
m
m
m 和
n
n
n 分别表示字符串 word1
和 word2
的长度。
空间复杂度: O ( m n ) O(mn) O(mn)。
写在最后
如果您发现文章有任何错误或者对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。
如果大家有更优的时间、空间复杂度的方法,欢迎评论区交流。
最后,感谢您的阅读,如果有所收获的话可以给我点一个 👍 哦。