字符串的编辑距离
2016-09-05 16:50
218 查看
题目:
对于一个字符串a可以通过增加一个字符、删除一个字符、修改一个字符,将字符串a变成字符串b,例如
a= abcddefg
b = abcefg
可以通过a字符串删除两个dd得到b字符串,也可以通过b字符串增加dd编程a字符串,从上面的分析可以知道,增加和删除的代价必须是相同的,这样a字符串变成b字符串的代价和b字符串变成a字符串的代价才会是相同的,否这可能产生代价不对称的情况。其实我们可以设定修改和增加(删除)的代价是不同的,当然也可以认为他们是一样的。
实际的计算过程可以如下进行:
1)比较a[i]和b[j];
2)如果a[i] == b[j],那么distance = EditDistance(a[i + i], b[j + 1]) + 0;
3)如果a[i] != b[j],那么可以经过如下操作使得a[i]等于b[j]
a) a[i]前增加b[j],那么distance = EditDistance(a[i], b[j + 1] + insert_cost
b)b[j]前增加a[i],那么distance = EditDistance(a[i + 1], b[j]) + insert_cost
c)删除a[i],那么distance = EditDistance(a[i + 1], b[j]) + delete_cost
d)删除b[j],那么distance = EditDistance(a[i], b[j + 1] + delete_cost
e)a[i]变成b[j],那么distance = EditDistance(a[i + 1], b[j + 1] + replace_cost
f)b[j]变成a[i],那么distance = EditDistance(a[i + 1], b[j + 1] + replace_cost
如果insert_cost == delete_cost,那么a添加字符变成b和b删除字符变成a是等价的,a[i]变成b[j]与b[j]变成a[i]也是等价的,因此实际需要考虑的代价就是下面3种情况:
i) distance = EditDistance(a[i], b[j + 1] + insert_cost(或delete_cost)
ii) distance = EditDistance(a[i + 1], b[j] + insert_cost(或delete_cost)
iii)distance = EditDistance(a[i + 1], b[j + 1] + replace_cost
如果我们回顾一下最长公共子序列问题(LCS),就会发现这个问题和LCS问题几乎是等价的。因为可以这样理解,找出a和b的LCS,保持LCS对齐不变,增加删除一些字符就完成了变换,而这样的代价应该是最小的(猜测的,没有证明)
这样一个问题,我们可以使用递归来解决。
当然的解决方案是用动态规划的方法解决,采用动态规划解决时,我们假设前面字符串都已经变换相同了,那么在a[i]变成b[j]的过程中需要对比如下代价:
1)如果a[i] == b[j],那么前面的状态可能是a[i - 1] b[j - 1]或者 a[i - 1] b[j]或者a[i] b[j - 1],我们要比较这些可能的转换过程中哪个代价更小;
2)如果a[i] != b[j],那么:
i)a[i] b[j]可能从a[i - 1] b[j - 1]状态通过replace a[i] to a[j] + replace的代价来实现;
ii)a[i] b[j]可能从a[i ] b[j - 1]状态通过为a[i]前面添加一个b[j -1] + insert的代价来实现;
iii)a[i] b[j]可能从a[i - 1] b[j]状态通过删除a[i - 1] + delete的代价来实现;
而这些代价就通过一个向量cost向量来存储。
程序代码如下:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main ()
{
string s1,s2;
while( cin>>s1>>s2)
{
int len1 = s1.size();
int len2 = s2.size();
vector<vector<int>> dp(len1+1, vector<int>(len2+1,0));
for(int i = 0; i <= len1; i++)
dp[i][0] = i;
for(int i = 0; i <= len2; i++)
dp[0][i] = i;
//
for(int i = 1; i <= len1; i++){
for(int j = 1; j <= len2; j++){
if(s1[i-1] == s2[j-1])//这个地方注意,调了好久(是i-1&&j-1不是i&&j)
dp[i][j] = dp[i-1][j-1];
else{
int tmp = min(dp[i-1][j], dp[i][j-1]);
dp[i][j] = 1 + min(tmp, dp[i-1][j-1]);
}
}
}
cout<<'1'<<'/'<<(dp[len1][len2]+1)<<endl;
}
return 0;
}
对于一个字符串a可以通过增加一个字符、删除一个字符、修改一个字符,将字符串a变成字符串b,例如
a= abcddefg
b = abcefg
可以通过a字符串删除两个dd得到b字符串,也可以通过b字符串增加dd编程a字符串,从上面的分析可以知道,增加和删除的代价必须是相同的,这样a字符串变成b字符串的代价和b字符串变成a字符串的代价才会是相同的,否这可能产生代价不对称的情况。其实我们可以设定修改和增加(删除)的代价是不同的,当然也可以认为他们是一样的。
实际的计算过程可以如下进行:
1)比较a[i]和b[j];
2)如果a[i] == b[j],那么distance = EditDistance(a[i + i], b[j + 1]) + 0;
3)如果a[i] != b[j],那么可以经过如下操作使得a[i]等于b[j]
a) a[i]前增加b[j],那么distance = EditDistance(a[i], b[j + 1] + insert_cost
b)b[j]前增加a[i],那么distance = EditDistance(a[i + 1], b[j]) + insert_cost
c)删除a[i],那么distance = EditDistance(a[i + 1], b[j]) + delete_cost
d)删除b[j],那么distance = EditDistance(a[i], b[j + 1] + delete_cost
e)a[i]变成b[j],那么distance = EditDistance(a[i + 1], b[j + 1] + replace_cost
f)b[j]变成a[i],那么distance = EditDistance(a[i + 1], b[j + 1] + replace_cost
如果insert_cost == delete_cost,那么a添加字符变成b和b删除字符变成a是等价的,a[i]变成b[j]与b[j]变成a[i]也是等价的,因此实际需要考虑的代价就是下面3种情况:
i) distance = EditDistance(a[i], b[j + 1] + insert_cost(或delete_cost)
ii) distance = EditDistance(a[i + 1], b[j] + insert_cost(或delete_cost)
iii)distance = EditDistance(a[i + 1], b[j + 1] + replace_cost
如果我们回顾一下最长公共子序列问题(LCS),就会发现这个问题和LCS问题几乎是等价的。因为可以这样理解,找出a和b的LCS,保持LCS对齐不变,增加删除一些字符就完成了变换,而这样的代价应该是最小的(猜测的,没有证明)
这样一个问题,我们可以使用递归来解决。
当然的解决方案是用动态规划的方法解决,采用动态规划解决时,我们假设前面字符串都已经变换相同了,那么在a[i]变成b[j]的过程中需要对比如下代价:
1)如果a[i] == b[j],那么前面的状态可能是a[i - 1] b[j - 1]或者 a[i - 1] b[j]或者a[i] b[j - 1],我们要比较这些可能的转换过程中哪个代价更小;
2)如果a[i] != b[j],那么:
i)a[i] b[j]可能从a[i - 1] b[j - 1]状态通过replace a[i] to a[j] + replace的代价来实现;
ii)a[i] b[j]可能从a[i ] b[j - 1]状态通过为a[i]前面添加一个b[j -1] + insert的代价来实现;
iii)a[i] b[j]可能从a[i - 1] b[j]状态通过删除a[i - 1] + delete的代价来实现;
而这些代价就通过一个向量cost向量来存储。
程序代码如下:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main ()
{
string s1,s2;
while( cin>>s1>>s2)
{
int len1 = s1.size();
int len2 = s2.size();
vector<vector<int>> dp(len1+1, vector<int>(len2+1,0));
for(int i = 0; i <= len1; i++)
dp[i][0] = i;
for(int i = 0; i <= len2; i++)
dp[0][i] = i;
//
for(int i = 1; i <= len1; i++){
for(int j = 1; j <= len2; j++){
if(s1[i-1] == s2[j-1])//这个地方注意,调了好久(是i-1&&j-1不是i&&j)
dp[i][j] = dp[i-1][j-1];
else{
int tmp = min(dp[i-1][j], dp[i][j-1]);
dp[i][j] = 1 + min(tmp, dp[i-1][j-1]);
}
}
}
cout<<'1'<<'/'<<(dp[len1][len2]+1)<<endl;
}
return 0;
}
相关文章推荐
- 最小编辑代价&&华为OJ 编辑距离&&计算字符串的相似度
- 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 利用编辑距离(Edit Distance)计算两个字符串的相似度
- 字符串编辑距离
- 算法学习(十二)最大连续乘积子串、字符串编辑距离
- 字符串编辑距离问题
- (51Nod 1183 编辑距离)字符串编辑距离
- 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 字符串相似度算法(编辑距离算法 Levenshtein Distance)
- 求两个字符串的编辑距离
- 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 字符串编辑距离
- 序列试题---最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离 .
- 两个字符串的编辑距离-动态规划方法
- 字符串的修改(动态规划-最短编辑距离)
- 动态规划 - 字符串的编辑距离
- 动态规划问题学习路线:斐波那契数列,最大递增子序列,松鼠捡苹果,最大公共子序列,字符串编辑距离
- 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 【Algorithm】字符串编辑距离(Levenshtein距离)C++算法实现
- LeetCode:Edit Distance(字符串编辑距离DP)