2019独角兽企业重金招聘Python工程师标准>>>
编辑距离是针对二个字符串(例如英文字)的差异程度的量化量测,量测方式是看至少需要多少次的处理才能将一个字符串变成另一个字符串。编辑距离可以用在自然语言处理中,例如拼写检查可以根据一个拼错的字和其他正确的字的编辑距离,判断哪一个(或哪几个)是比较可能的字。(维基百科)
举个栗子:
abc->ab 只需要将abc的c删除可以变为ab 编辑距离为1;
ab->abc 只需要在ab的末尾加上c可以变为abc 编辑距离为1;
abd->abc 只需要将d字符串替换为c可以变为abc 编辑距离为1;
所有的操作仅仅有以上三种基本操作。
那么定义一个字符串"monkey"最少经过多少次可以变为变为"online"?
假设有两个字符串 s t ,其中s的长度为 m s[1-m],t的长度为n t[1-m]。
d[i][j]表示字符串s[1-i]到字符串m[1-j]的编辑距离。
- 当 s[i] 等于 b[j] 时,
d[i][j] = d[i-1][j-1]
, 比如 abc -> adc 的编辑距离等于 ab -> ad 的编辑距离 - 当 s
[i]
不等于 b[j]
时,d[i][j]
等于如下 3 项的最小值:d[i-1][j]
+ 1(删除s[i]
), 比如 adf -> abc 的编辑距离 = ab -> abc 的编辑距离 + 1d[i][j-1]
+ 1(插入t[j]
), 比如 adf -> abc 的编辑距离 = adfc -> abc 的编辑距离 + 1 = adf -> ab 的编辑距离 + 1d[i-1][j-1]
+ 1(将s[i]
替换为t[j]
), 比如 xyz -> abc 的编辑距离 = xyc -> abc 的编辑距离 + 1 = xy -> ab 的编辑距离 + 1
递归边界:
d[i][0] = i
, t 字符串为空,表示将 s[1]-s[i]
全部删除,编辑距离为 i。d[0][j] = j
, s 字符串为空,表示 t 插入 s[1]-s[j]
,编辑距离为 j。
根据条件写出递归代码如下:
/**
* @param s 字符串s
* @param t 字符串t
* @param s_i s.length-1
* @param t_j t.length-1
* @return 编辑距离
*/
private static int edit_Distance(String s,String t,int s_i,int t_j){
if (s_i==0){
return t_j;
}
if (t_j==0){
return s_i;
}
char s_c=s.charAt(s_i);
char t_c=t.charAt(t_j);
if (s_c==t_c){
return edit_Distance(s,t,s_i-1,t_j-1);
}
return min(edit_Distance(s,t,s_i-1,t_j-1),edit_Distance(s,t,s_i-1,t_j),edit_Distance(s,t,s_i,t_j-1))+1;
}
递归操作其中存在很严重的问题,效率低下,时间复杂度是指数增长。
递归的思想是从后向前计算,我们可以从前向后计算,并且储存每一步计算的值,避免重复计算。
比如S:abc->T:abd 建立一个矩阵
0 | a | b | c | |
0 | 0 | 1 | 2 | 3 |
a | 1 | 0 | ||
b | 2 | |||
d | 3 |
比如此时需要计算dp[2,2] 那么需要在dp[1,2]+1 dp[2,1]+1 dp[1,1]+(s[1]==t[1]?0:1))这三个中找出最小的一个 为0 依次计算每个单元格 最终右下角dp[4][4]为最终的编辑距离。
动态规划实现代码如下:
/**
* 动态规划的方式实现
* @param s 字符串s
* @param t 字符串t
* @return 编辑距离
*/
private static int editDistance(String s,String t){
int sLength=s.length();
int tLength=t.length();
//判断特殊情况
if (sLength==0){
return tLength;
}
if (tLength==0){
return sLength;
}
//构建矩阵 储存中间结果
int[][] dp=new int[sLength+1][tLength+1];
//初始化矩阵
for (int i=0;i<=sLength;i++){
dp[i][0]=i;
}
for (int i=0;i<=tLength;i++){
dp[0][i]=i;
}
//分步求解
for (int i=1;i<=sLength;i++){
char si=s.charAt(i-1);
for (int j=1;j<=tLength;j++){
char tj=t.charAt(j-1);
int cost=si==tj?0:1;
int z=min(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+cost);
dp[i][j]=z;
}
}
//最终结果
return dp[sLength][tLength];
}
private static int min(int a,int b,int c){
int tmp=a
测试数据以及测试结果: