求两个字符串的编辑距离

  很多程序都需要利用到字符串的比较,而字符串的编辑距离在字符串相似性比较中,应用广泛。下面分享字符串编辑距离的求解。

概念

  字符串的编辑距离,又称为Levenshtein距离,由俄罗斯的数学家Vladimir Levenshtein在1965年提出。是指利用字符操作,把字符串A转换成字符串B所需要的最少操作数。其中,字符操作包括:

  • 删除一个字符
  • 插入一个字符
  • 修改一个字符

  例如对于字符串"if"和"iff",可以通过插入一个'f'或者删除一个'f'来达到目的。

  一般来说,两个字符串的编辑距离越小,则它们越相似。如果两个字符串相等,则它们的编辑距离(为了方便,本文后续出现的“距离”,如果没有特别说明,则默认为“编辑距离”)为0(不需要任何操作)。不难分析出,两个字符串的编辑距离肯定不超过它们的最大长度(可以通过先把短串的每一位都修改成长串对应位置的字符,然后插入长串中的剩下字符)。

问题描述

  给定两个字符串A和B,求字符串A至少经过多少步字符操作变成字符串B。

问题分析

  1)首先考虑A串的第一个字符

  假设存在两个字符串A和B,他们的长度分别是lenA和lenB。首先考虑第一个字符,由于他们是一样的,所以只需要计算A[2...lenA]和B[2...lenB]之间的距离即可。那么如果两个字符串的第一个字符不一样怎么办?可以考虑把第一个字符变成一样的(这里假设从A串变成B串):

  • 修改A串的第一个字符成B串的第一个字符,之后仅需要计算A[2...lenA]和B[2...lenB]的距离即可;
  • 删除A串的第一个字符,之后仅需要计算A[2...lenA]和B[1...lenB]的距离即可;
  • 把B串的第一个字符插入到A串的第一个字符之前,之后仅需要计算A[1...lenA]和B[2...lenB]的距离即可。

  2)接下来考虑A串的第i个字符和B串的第j个字符。

  我们这个时候不考虑A的前i-1字符和B串的第j-1个字符。如果A串的第i个字符和B串的第j个字符相等,即A[i]=B[j],则只需要计算A[i...lenA]和B[j...lenB]之间的距离即可。如果不想等,则:

  • 修改A串的第i个字符成B串的第j个字符,之后仅需要计算A[i+1...lenA]和B[j+1...lenB]的距离即可;
  • 删除A串的第i个字符,之后仅需要计算A[i+1...lenA]和B[j...lenB]的距离即可;
  • 把B串的第j个字符插入到A串的第i个字符之前,之后仅需要计算A[i...lenA]和B[j+1...lenB]的距离即可。

  写到这里,自然会想到用递归求解或者动态规划求解,由于用递归会产生很多重复解,所以用动态规划。

构建动态规划方程

  用edit[i][j]表示A串从第i个字符开始和B串从第j个字符开始的距离。则从上面的分析,不难推导出动态规划方程:

,其中

代码

  有了动态规划方程,程序自然也就不难写了。下面贴出我的Java代码

        /**
     * 计算两个字符串的编辑距离
     * @param str1 需要比较的字符串
     * @param str2 需要比较的字符串
     * @return 两个字符串的编辑距离
     */
    public int editDistance(String str1,String str2){
        
        int lenStr1=str1.length();
        int lenStr2=str2.length();
        int[][] edit=new int[lenStr1][lenStr2];
        for(int i=0;i<lenStr1;i++){
            edit[i][0]=i;
        }
        for(int j=0;j<lenStr2;j++){
            edit[0][j]=j;
        }
        
        for(int i=1;i<lenStr1;i++){
            for(int j=1;j<lenStr2;j++){
                edit[i][j]=Integer.min(edit[i-1][j]+1,edit[i][j-1]+1);
                if(str1.charAt(i-1)==str2.charAt(j-1)){
                    edit[i][j]=Integer.min(edit[i][j], edit[i-1][j-1]);
                }else{
                    edit[i][j]=Integer.min(edit[i][j], edit[i-1][j-1]+1);
                }
            }
        }
        
        return edit[lenStr1-1][lenStr2-1];
    }
editDistance

  注:代码并没有过多测试,如有错误,请留言评论,谢谢。

转载于:https://www.cnblogs.com/xiuyangleiasp/p/5023717.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值