关于两个字符串s1,s2的差别,可以通过计算他们的最小编辑距离来决定。
所谓的编辑距离: 让s1和s2变成相同字符串需要下面操作的最小次数。
1. 把某个字符ch1变成ch2
2. 删除某个字符
3. 插入某个字符
例如 s1 = “12433” 和s2=”1233”;
则可以通过在s2中间插入4得到12433与s1一致。
即 d(s1,s2) = 1 (进行了一次插入操作)
编辑距离的性质
计算两个字符串s1+ch1, s2+ch2的编辑距离有这样的性质:
1. d(s1,””) = d(“”,s1) = |s1| d(“ch1”,”ch2”) = ch1 == ch2 ? 0 : 1;
2. d(s1+ch1,s2+ch2) = min( d(s1,s2)+ ch1==ch2 ? 0 : 1 ,
d(s1+ch1,s2) + 1,
d(s1,s2+ch2) + 1 );
网的其他版本没有这个+1,没有+1是错误的!
第一个性质是显然的。
第二个性质: 由于我们定义的三个操作来作为编辑距离的一种衡量方法。
于是对ch1,ch2可能的操作只有
1. 把ch1变成ch2
2. s1+ch1后删除ch1 d = (1+d(s1,s2+ch2))
3. s1+ch1后插入ch2 d = (1 + d(s1+ch1,s2))
对于2和3的操作可以等价于:
_2. s2+ch2后添加ch1 d=(1+d(s1,s2+ch2))
_3. s2+ch2后删除ch2 d=(1+d(s1+ch1,s2))
因此可以得到计算编辑距离的性质2。
其变种有:
string const str1 = "12433";
string const str2 = "12222";
vector<vector<int>> mem(str1.size() + 1, vector<int>(str2.size() + 1, -1));
int Distance(int i, int j){
if (mem[i][j] == -1){
if (i == 0 && j == 0){
mem[i][j] = 0;
}
else if (i == 0 || j == 0){
mem[i][j] = max(i, j);
}
else{
mem[i][j] = min(min( Distance(i - 1, j) + 1
, Distance(i, j - 1)) + 1
, Distance(i - 1, j - 1) + (str1[i - 1] == str2[j - 1] ? 0 : 1));
}
}
return mem[i][j];
}
void main(){
cout << Distance(str1.size(), str2.size()) << endl;
return;
}