java+编辑距离自动机_编辑距离(Edit Distance)的原理,利用递归以及动态规划的实现。...

编辑距离是针对二个字符串(例如英文字)的差异程度的量化量测,量测方式是看至少需要多少次的处理才能将一个字符串变成另一个字符串。编辑距离可以用在自然语言处理中,例如拼写检查可以根据一个拼错的字和其他正确的字的编辑距离,判断哪一个(或哪几个)是比较可能的字。(维基百科)

举个栗子:

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 的编辑距离 + 1

d[i][j-1] + 1(插入 t[j]), 比如 adf -> abc 的编辑距离 = adfc -> abc 的编辑距离 + 1 = adf -> ab 的编辑距离 + 1

d[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

return tmp

}

测试数据以及测试结果:

04378c801008b8dec8961a1c726a40ff.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值