Given two words word1 and word2,find the minimum number of steps required to convert word1 to word2.(each operation is counted as 1 step.)
You have the following 3 operations permitted on a word:
a) Insert a character
b) Delete a character
c) Replace a character
所谓的求字符串的编辑距离就是给你两个字符串A和B,每次对A进行下列三个操作之一:
1) 改变一个字符
2) 删除一个字符
3) 增加一个字符
将A变成B所需要的最小步骤数就是AB之间的编辑距离。
1如何使用笔算出AB之间的编辑距离
首先分析AB的长度,对其中较短的字符串进行加0填充,使填充之后的字符串长度相等,并且保证填充后的字符串之间每一位尽可能的相等,比如A是aabbcc,B为aawbbwccw,那么A填充之后变成A^:aa0bb0cc0,需要注意的是,0并不是一个字符,只是表示一个占位,
这时可以得到A和B 的编辑距离,将A^和B一一对应,不相等的位数的个数就是A到B所需要的最短编辑距离,同时也是B变成A的最短编辑距离,这里为3
2AB之间的编辑距离计算编程思路
1) AB最后一位相等
设A长度为i位,B长度为j位,d(i,j)为A,B之间的编辑距离,当A[i]==B[j]的时候,对其中较短的一个字符串进行加0填充,这里假设是A,填充后为A^,那么在填充之后B[j]所对应的字符有两种情况,其一是B[j]对应A[i],那么这里很明显,d(i,j)==d(i-1,j-1)成立,当B[j]对应0的时候,这是可以在不改变编辑距离的情况下对A^进行更改,将A^的最后一个0与前一个与B[j]相等的字符交换位置,这个时候A^和B之间的不同位数不会改变,编辑距离也就不会改变,这个时候d(i,j)==d(i-1,j-1)成立
2) AB最后一位不等
当AB最后一位不等的时候,A^和B最后一位有两种情况,0和一个字符,这个假设A^最后为0,那么最后一步为插入字符,那么d(i,j)=d(i,j-1)+1,当A^和B最后一位为两个不同字符的时候,那么最后一步为更改字符,d(i,j)=d(i-1,j-1)+1,
3) 递推公式
综上所述,能很容易的得到AB之间编辑距离的递推公式,
d(i,j)=min{d(i-1,j-1)+@(A[i],B[j]),d(i-1,j)+1,d(i,j-1)+1}
@(A[i],B[j])的值当A[i]==B[j]时为0,当A[i]!=B[j]时为1
接下来是递归的算法,但是这样的递归写法可能会导致超时,我的这个算法就超时了,所以接下来使用循环的非递归算法来解决这个问题
通过这个问题的学习我学会了vector二维数组的写法,类似于这样:vector<vector<int>> dp(word1.length()+1, vector<int>(word2.length()+1,-1));
class Solution {
public:
int f(int i, int j,vector<vector<int>> dp,string word1,string word2)
{
if (dp[i][j] != -1)
return dp[i][j];
if (word1[i-1] == word2[j-1])
return dp[i][j]=f(i - 1, j - 1, dp,word1, word2);
else return dp[i][j] = 1+min(f(i - 1, j -1, dp, word1, word2),min(f(i, j - 1, dp, word1, word2), f(i - 1, j, dp, word1,word2)));
}
intminDistance(string word1, string word2) {
vector<vector<int>>dp(word1.length()+1, vector<int>(word2.length()+1,-1));
for (int i = 0; i <= word1.length();i++) dp[i][0] = i;
for (int i = 0; i <= word2.length();i++) dp[0][i] = i;
return f(word1.length(), word2.length(),dp,word1,word2);
}
};
非递归算法:
class Solution {
public:
int minDistance(string word1, string word2){
vector<vector<int>>dp(word1.length()+1, vector<int>(word2.length()+1,-1));
for (int i = 0; i <= word1.length();i++) dp[i][0] = i;
for (int i = 0; i <= word2.length();i++) dp[0][i] = i;
for (int i = 1; i <= word1.length();i++)
for (int j = 1; j <=word2.length(); j++)
if (word1[i-1] == word2[j-1])dp[i][j] = dp[i - 1][j - 1];
else
{
dp[i][j] = 1+min(dp[i -1][j - 1], min(dp[i][j - 1], dp[i - 1][j]));
}
return dp[word1.length()][word2.length()];
}
};