编辑距离是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。
设dp[i][j]表示str1的0到i位置的子串转换成str2的0到j位置的子串所需的最小编辑距离,则有
dp[i, j] := minimum(
dp[i-1, j] + 1, //在str1上i位置删除字符(或者在str2上j-1位置插入字符)
dp[i, j-1] + 1, //在str1上i-1位置插入字符(或者在str2上j位置删除字符)
dp[i-1, j-1] + cost // 替换操作
很容易就能写出动规代码:
时间复杂度O(m*n),空间复杂度O(m*n)
class Solution {
public:
int minDistance(string word1, string word2) {
int m=word1.size();
int n=word2.size();
vector<vector<int>> dis(m+1);
for(int i=0;i<=m;i++)dis[i].assign(n+1,INT_MAX);
dis[0][0]=0;
for(int i=0;i<=m;i++)
for(int j=0;j<=n;j++){
if(i>0) dis[i][j] = min(dis[i][j],dis[i-1][j]+1); //delete
if(j>0) dis[i][j] = min(dis[i][j],dis[i][j-1]+1);//insert
//substitute
if(i>0&&j>0)
{
if(word1[i-1]!=word2[j-1])
dis[i][j] = min(dis[i][j],dis[i-1][j-1]+1);
else
dis[i][j] = min(dis[i][j],dis[i-1][j-1]);
}
}
return dis[m][n];
}
};
将空间进行优化,注意到dp[i][j]只与dp[i-1][j],dp[i-1][j-1],dp[i][j-1]有关,所以可以将二维数组变成一维数组来处理,即滚动数组
class Solution {
public:
int minDistance(string word1, string word2) {
int f[word2.length()+1];
int upper_left=0;//记录f[i-1][j-1];
for(size_t i=0;i<=word2.size();++i)
f[i]=i;
for(size_t i=1;i<=word1.size();++i){
upper_left=f[0];
f[0]=i;
for(size_t j=1;j<=word2.size();++j){
int upper=f[j];
if(word1[i-1]==word2[j-1])
f[j]=upper_left;
else
f[j]=1+min(upper_left,min(f[j],f[j-1])); //f[j-1]表示dp[i][j-1],f[j]表示dp[i][j]
upper_left=upper;
}
}
return f[word2.length()];
}
};
还有一类问题也属于编辑距离问题,即用于DNA的比对问题:
问题描述:
DNA在复制的时候可能出现的偏差是(理论上,对每个碱基被复制时,都可能出现偏差):
1. 漏掉某个脱氧核苷酸。例如把 AGGT 复制成为:AGT
2. 错码,例如把 AGGT 复制成了:AGCT
3. 重码,例如把 AGGT 复制成了:AAGGT
如果某DNA串a,最少要经过 n 次出错,才能变为DNA串b,则称这两个DNA串的距离为 n。
例如:AGGTCATATTCC 与 CGGTCATATTC 的距离为 2
这其实也就是编辑距离的变形,代码同上