题目描述
UNIX系统下有一个行编辑器ed,它每次只对一行文本做删除一个字符、插入一个字符或替换一个字符三种操作。例如某一行的内容是“ABC”,经过把第二个字符替换成“D”、删除第一个字符、末尾插入一个字符“B”,这三步操作后,内容就变成了“DCB”。即“ABC”变成“DCB”需要经过3步操作,我们称它们的编辑距离为3。
现在给你两个任意字符串(不包含空格),请帮忙计算它们的最短编辑距离。
输入描述:
输入包含多组数据。
每组数据包含两个字符串m和n,它们仅包含字母,并且长度不超过1024。
输出描述:
对应每组输入,输出最短编辑距离。
分析:
使用dp[i][j]代表字符串将串str1[0…i-1]转换为串str2[0…j-1]所需的最少操作次数(最短距离)
iteration:
d
p
[
i
]
[
j
]
=
{
d
p
[
i
−
1
]
[
j
]
+
1
,
插
入
d
p
[
i
]
[
j
−
1
]
+
1
,
删
除
d
p
[
i
−
1
]
[
j
−
1
]
+
(
s
t
r
1
[
i
−
1
]
!
=
s
t
r
2
[
j
−
1
]
)
替
换
dp[i][j] = \left\{ \begin{array}{lr} dp[i-1][j]+1, & 插入 \\ dp[i][j-1] +1, & 删除 \\ dp[i-1][j-1] + (str1[i-1] != str2[j-1]) & 替换 \end{array} \right.
dp[i][j]=⎩⎨⎧dp[i−1][j]+1,dp[i][j−1]+1,dp[i−1][j−1]+(str1[i−1]!=str2[j−1])插入删除替换
base:
d
p
[
i
]
[
0
]
=
i
,
d
p
[
0
]
[
j
]
=
j
.
dp[i][0] = i, \\ dp[0][j] = j.
dp[i][0]=i,dp[0][j]=j.
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
using namespace std;
int dp[1025][1025];
int main(){
string str1, str2;
while(cin >> str1 >> str2){
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= str1.size(); ++i) dp[i][0] = i;
for(int j = 1; j <= str2.size(); ++j) dp[0][j] = j;
for(int i = 1; i <= str1.size(); ++i){
for(int j = 1; j <= str2.size(); ++j){
dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1);
dp[i][j] = min(dp[i][j], dp[i-1][j-1] + (str1[i-1] != str2[j-1]));
}
}
cout << dp[str1.size()][str2.size()] << endl;
for(int i = 1; i <= str1.size(); ++i){
for(int j = 1; j <= str2.size(); ++j){
cout << dp[i][j] << ' ';
} cout <<endl;
}
}
return 0;
}
LeetCode上的相同题目:https://leetcode.com/problems/edit-distance/
因为dp[i][j]在更新的时候只与dp[i-1]这一行有关,所以我们可以进一步压缩空间利用率至
O
(
m
i
n
(
m
,
n
)
)
O(min(m, n))
O(min(m,n)),其中
m
m
m,
n
n
n为两个字符串的长度。
class Solution {
public:
int minDistance(string word1, string word2) {
if(word1.size() == 0) return word2.size();
if(word2.size() == 0) return word1.size();
/* const修饰的是char, 指针指向的内容不能改变, 指针可以改变 */
const char* str1 = word1.c_str();
const char* str2 = word2.c_str();
int len1 = word1.size(), len2 = word2.size();
if(word1.size() < word2.size()) {
swap(str1, str2);
swap(len1, len2);
}
vector<int> dp(len2+1);
int pre; // dp[i-1][j-1]
int candi; // new dp[i][j]
for(int j = 1; j <= len2; ++j) dp[j] = j; // dp[0][j], 当i==1时用来更新pre
for(int i = 1; i <= len1; ++i){
dp[0] = i; // dp[i][0] = i
pre = i-1; // dp[i-1][0]
for(int j = 1; j <= len2; ++j){
candi = min(dp[j], dp[j-1]) + 1; // dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + 1
candi = min(candi, pre + (str1[i-1] != str2[j-1])); // dp[i][j] = min(dp[i][j], dp[i-1][j-1]) + (str1[i-1]!= str2[j-1])
pre = dp[j]; // record dp[i-1][j-1]
dp[j] = candi;
}
} return dp[len2];
}
};
参考链接:
https://www.jianshu.com/p/7ed1ba268d77
https://blog.youkuaiyun.com/yutianzuijin/article/details/50273335