字符串编辑距离与拼写错误检查

一、贝叶斯定理

编辑距离是指两个字符串之间,由一个转换成另一个所需的最少编辑操作次数。编辑操作包括删除、添加(插入)和替换三种方式。当然,次数越小越相似。

编辑距离应用最多的地方就是基于贝叶斯定理的拼写检查中,贝叶斯公式:


用户输入一个单词时,可能拼写正确,也可能拼写错误。如果把拼写正确的情况记做c(代表correct),拼写错误的情况记做w(代表wrong),那么"拼写检查"要做的事情就是:在发生w的情况下,试图推断出c。换言之:已知w,然后在若干个备选方案中,找出可能性最大的那个c,也就是求的最大值。
而根据贝叶斯定理,有:

  

由于对于所有备选的c来说,对应的都是同一个w,所以它们的P(w)是相同的,因此我们只要最大化

即可。其中:

  • P(w|c)表示在试图拼写c的情况下,出现拼写错误w的概率。为了简化问题,假定两个单词在字形上越接近,就有越可能拼错,P(w|c)就越大。举例来说,相差一个字母的拼法,就比相差两个字母的拼法,发生概率更高。你想拼写单词genius,那么错误拼成genious(相差一个字母)的可能性,就比拼成genioous高(相差两个字母),而这种问题就是“编辑距离”问题。
  • P(c)表示某个正确的词的出现"概率",它可以用"频率"代替。如果我们有一个足够大的文本库,那么这个文本库中每个单词的出现频率,就相当于它的发生概率。某个词的出现频率越高,P(c)就越大。比如在你输入一个错误的词“genious”时,系统更倾向于去猜测你可能想输入的词是“genius”,而不是“genieus”,因为“genius”更常见。

所以我们首先找出P(w|c)很大的那些单词,怎么找呢?用编辑距离方法(任意单词与输入错误单词之间,源是任意单词,目标单词是输入的(错误)单词),操作次数越少,说明越相似,从而其概率P(w|c)就越大,然后在文本库中找出这个概率很大的单词对应的频率P(c)(P(w|c)很大,P(c)不见得很大),从而可以计算出贝叶斯概率,概率大者作为提示显示出来。如:



二、字符串编辑距离


举个例子:S=“eeba” ,T="abac" 。我们发现当S只有一个字符e、T只有一个字符a的时候,我们马上就能得到S和T的编辑距离edit(0,0)=1(将e替换成a)。那么如果S中有1个字符e、T中有两个字符ab的时候,我们是不是可以这样分解:edit(0,1)=edit(0,0)+1(将e替换成a后,在添加一个b)。如果S中有两个字符ee,T中有两个字符ab的时候,我们是不是可以分解成:edit(1,1)=min(edit(0,1)+1, edit(1,0)+1, edit(0,0)+f(1,1))。 这样我们可以得到这样一些动态规划公式:      
        如果i=0且j=0        edit(0, 0)=1
        如果i=0且j>0        edit(0, j )=edit(0, j-1)+1
        如果i>0且j=0        edit( i, 0 )=edit(i-1, 0)+1   //以上三行是初始化二维数组时的操作
        如果i>0且j>0        edit(i, j)=min(edit(i-1, j)+1, edit(i,j-1)+1, edit(i-1,j-1)+f(i , j) )    //f(i , j) =0 or 1
 
注:

1) edit(i,j)表示S中[0.... i]的子串 si 到T中[0....j]的子串t1的编辑距离。f(i,j)表示S中第i个字符s(i)转换到T中第j个字符s(j)所需要的操作次数,如果s(i)==s(j),则不需要任何操作f(i, j)=0; 否则,需要替换操作,f(i, j)=1 。

2) edit(i-1, j)+1:删除操作; 

    edit(i,j-1)+1: 添加操作; 

    edit(i-1,j-1)+f(i , j):替换操作,等价于edit(i-1,j-1)+(s[i] = t[j] ? 0: 1)

    

递推公式可以这样理解:

我们对字符可能进行的操作有三种:

           如果我们可以使用k个操作数把s[1…i]转换为t[1…j-1],我们只需要把t[j]加在最后面就能将s[1…i]转换为t[1…j],操作数为k+1;

           如果我们可以使用k个操作数把s[1…i-1]转换为t[1…j],我们只需要把s[i]从最后删除就可以完成转换,操作数为k+1;

           如果我们可以使用k个操作数把s[1…i-1]转换为t[1…j-1],我们只需要在需要的情况下(s[i] != t[j])把s[i]替换为t[j],所需的操作数为k+cost(cost

代表是否需要转换,如果s[i]==t[j],则cost为0,否则为1)。


将s[1…n]转换为t[1…m]当然需要将所有的s转换为所有的t,所以,d[n,m](表格的右下角)就是我们所需的结果。

另外,必须记住一点:这所有的操作都是针对i,即源字符串的。如,删除的是源字符串i上的字符...


代码如下:

int getDistance(char[] str1,char[] str2)
{
     int n = str1.length;
     int m = str2.length;
     int[][] C = new int[n+1][m+1];
     int i, j, x, y, z;
     for (i = 0; i <n; i++)
         C[i][0] = i;
     for (i = 0; i < m; i++)
         C[0] [i] = i;
     for (i = 1; i < n+1; i++)
    {
         for (j = 1; j < m+1; j++)
         {
             x = c[i][j-1] + 1;
             y = c[i-1][j] + 1;
             if (str1[i] == str2[j])
                 z = c[i-1][j-1];
             else
                 z = c[i-1][j-1] + 1;
                 
             c[i][j] = min(min(x, y), z);
          }
     }
     return c[n][m];  
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值