一、题意
给你两个单词word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
二、解法
解法:
动态规划
dp[i][j]表示word1前i个字符变换到word2前j个字符的编辑距离。
首先初始化dp[0][i]=i;dp[i][0]=i;
因为将i个字符变成0个需要i步操作。
判断word1[i]==word2[j]
相等:
则dp[i+1][j+1]=dp[i][j]; 没有增加一步操作。
不相等:
需要增加一步操作进行修改,
dp[i][j]=min(dp[i][j+1],dp[i+1][j],dp[i][j]) +1
dp[i][j+1]对word1进行添加操作
dp[i+1][j]对word1进行删除操作
dp[i][j]:替换操作
dp可以优化成两个数组 一个表示前一个状态,一个表示当前状态。
时间复杂度:
O
(
n
m
)
O(nm)
O(nm)
空间复杂度:
O
(
n
)
O(n)
O(n)
三、代码
解法:
int minDistance(string word1, string word2) {
int n = word1.size();
int m = word2.size();
vector<vector<int>> dp(n+1,vector<int>(m+1,0));
for(int i=1;i<=n;i++){
dp[i][0]=i;
}
for(int i=1;i<=m;i++){
dp[0][i]=i;
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(word1[i]==word2[j]){
dp[i+1][j+1] = dp[i][j];
}
else{
dp[i+1][j+1] = min(dp[i][j+1],min(dp[i+1][j],dp[i][j]))+1;
}
}
}
/*
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
printf("%d ",dp[i][j]);
}
printf("\n");
}*/
return dp[n][m];
}
int minDistance(string word1, string word2) {
int n = word1.size();
int m = word2.size();
vector<int> dp(m+1,0);
vector<int> preDp(m+1,0 );
for(int i=1;i<=m;i++){
preDp[i]=i;
}
for(int i=0;i<n;i++){
dp[0]=i+1;
for(int j=0;j<m;j++){
if(word1[i]==word2[j]){
dp[j+1] = preDp[j];
}
else{
dp[j+1] = min(preDp[j+1],min(dp[j],preDp[j]))+1;
}
}
preDp = dp;
}
return preDp[m];
}
四、总结
经典的动态规划问题,主要在不相等那里的状态转移要弄清楚。
五、引用
[1] leetcode:72. Edit Distance
[2] leetcode:72. Edit Distance官方解法