目录
引入
从各大OJ平台对其的收录,我们可以知道这道题是多么的经典。闲言少叙,书归正传。接下来我们进入正题。
题目
示例
数据规模与说明
思路解析
抓取关键字 “最少操作次数” ,所以我们很快反应过来这是一题最优化的题目。面对这种题目,不妨先找找 “最优子结构”。
假设我们获取到一个 “最优子结构”,即从 到
的最小操作次数。
PS:从 到
的最小操作次数,这无伤大雅。
值得注意的是,这个时候我们并不关心我们假设的最优子结构是如何获取得到的。只是单纯地反应我们总有方法能够获取最优子结构,所以假设我们处理的情形是可以获取得到最优子结构后。
接下来,我们就要思考如果我们现在要获取 到
的最小操作次数。此时,依据题意我们拥有三种操作(策略)。在变换之前,首要的就是分析各个策略对于的变换条件。只有得知了变换条件,我们才能够合理地运用策略来获取正确的最优子结构。
策略1:插入
首先,插入操作对于 与
的大小关系没有要求。其次他对两个字符串的长度也没有做出要求。也就是说,我们可以在任何情况下采取这个策略进行尝试。
再者,如果我们对 进行插入操作,那么一定有
,所以我们只要知道
到
的最小操作次数,而这是我们可以知道的。
策略2:删除
首先,删除操作跟插入操作一样,是可以在任何情况执行的。换一种角度来说,如果对 进行插入操作,其实就是对
进行删除操作。
那么,我们对 进行删除操作,也就是删除
,我们只需要知道
到
的最小操作次数即可。
策略3:替换
替换操作就与前两种操作体系不同,替换操作对 与
的大小关系有所要求。如果,二者相等就可以不执行,否则就可以尝试替换操作。相同的,无论执不执行,我们都需要知道
到
的最小操作次数。
得知了三种策略的使用尝试条件,那么我接下来就可以使用他们来获取正确的最优子结构。他们对应代码如下:
if( word1[i - 1] != word2[j - 1])
dp[i][j] = min(min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]) + 1;
else
dp[i][j] = min(min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1] - 1) + 1;//dp[i-1][j-1] - 1是为了抵消式子外+1的作用
通过上述的分析,我们也得知了如果要获取 dp[i][j] 则需要知道 dp[i-1][j], dp[i][j-1], dp[i-1][j-1] 三个状态值。其中 dp[i][j] 表示从 到
的最小操作次数。
# | R | O | S | |
# | 1 | 1 | 1 | 1 |
H | 1/1 | 2/1 | ... | ... |
O | 1 | 2 | ||
R | 1 | ... | ||
S | 1 | ... | ||
E | 1 | ... |
注:#表示空字符串,2表示我们在计算的,1表示我们需要获取的
通过打标我们知道,我们需要知道 第 0 行 和 第 0 列的情况。而这一部分的最小操作次数是显而易见的。# 与 的最小操作次数为 j 次。反之,同理。
所以,我们获取到初始化部分与其值。故而有以下代码:
for (int i = 1; i <= len_word1; ++i) dp[i][0] = i;
for (int i = 1; i <= len_word2; ++i) dp[0][i] = i;
最后我们获取到AC代码。
AC代码(leetcode)
class Solution {
public:
int minDistance(string word1, string word2) {
int len_word1 = word1.size();
int len_word2 = word2.size();
vector<vector<int>> dp(len_word1 + 1, vector<int>(len_word2 + 1, 0));
for (int i = 1; i <= len_word1; ++i) dp[i][0] = i;
for (int i = 1; i <= len_word2; ++i) dp[0][i] = i;
for(int i = 1; i <= len_word1; ++i) {
for (int j = 1; j <= len_word2; ++j) {
if( word1[i - 1] != word2[j - 1])
dp[i][j] = min(min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]) + 1;
else
dp[i][j] = min(min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1] - 1) + 1;
}
}
return dp[len_word1][len_word2];
}
};
AC代码(洛谷)
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
int minDistance(string word1, string word2) {
int len_word1 = word1.size();
int len_word2 = word2.size();
vector<vector<int>> dp(len_word1 + 1, vector<int>(len_word2 + 1, 0));
for (int i = 1; i <= len_word1; ++i) dp[i][0] = i;
for (int i = 1; i <= len_word2; ++i) dp[0][i] = i;
for(int i = 1; i <= len_word1; ++i) {
for (int j = 1; j <= len_word2; ++j) {
if( word1[i - 1] != word2[j - 1])
dp[i][j] = min(min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]) + 1;
else
dp[i][j] = min(min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1] - 1) + 1;
}
}
return dp[len_word1][len_word2];
}
};
int main() {
string word1, word2;
cin >> word1;
cin >> word2;
Solution A;
cout << A.minDistance(word1, word2);
return 0;
}
复杂度
时间复杂度 O(len_word1 * len_word2), 空间复杂度同时间复杂度。