最小编辑距离算法

概念

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

  • 删除一个字符     a) Insert a character
  • 插入一个字符     b) Delete a character
  • 修改一个字符     c) Replace a character

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

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

问题描述

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

问题分析

例如: 
我们有两个字符串: kitten 和 sitting: 
现在我们要将kitten转换成sitting 
我们可以做如下的一些操作;

k i t t e n –> s i t t e n 将K替换成S
sitten –> sittin 将 e 替换成i
sittin –> sitting 添加g

在这里我们设置每经过一次编辑,也就是变化(插入,删除,替换)我们花费的代价都是1。

算法基本步骤:

(1)构造 行数为m+1 列数为 n+1 的矩阵 , 用来保存完成某个转换需要执行的操作的次数,将串s[1..n] 转换到 串t[1…m] 所需要执行的操作次数为matrix[n][m]的值;

(2)初始化matrix第一行为0到n,第一列为0到m。

Matrix[0][j]表示第1行第j-1列的值,这个值表示将串s[1…0]转换为t[1..j]所需要执行的操作的次数,很显然将一个空串转换为一个长度为j的串,只需要j次的add操作,所以matrix[0][j]的值应该是j,其他值以此类推。

(3)检查每个从1到n的s[i]字符;

(4)检查每个从1到m的s[i]字符;

(5)将串s和串t的每一个字符进行两两比较,如果相等,则让cost为0,如果不等,则让cost为1(这个cost后面会用到);

(6)a、如果我们可以在k个操作里面将s[1..i-1]转换为t[1..j],那么我们就可以将s[i]移除,然后再做这k个操作,所以总共需要k+1个操作。

b、如果我们可以在k个操作内将 s[1…i] 转换为 t[1…j-1] ,也就是说d[i,j-1]=k,那么我们就可以将 t[j] 加上s[1..i],这样总共就需要k+1个操作。

c、如果我们可以在k个步骤里面将 s[1…i-1] 转换为 t [1…j-1],那么我们就可以将s[i]转换为 t[j],使得满足s[1..i] == t[1..j],这样总共也需要k+1个操作。(这里加上cost,是因为如果s[i]刚好等于t[j],那么就不需要再做替换操作,即可满足,如果不等,则需要再做一次替换操作,那么就需要k+1次操作)

因为我们要取得最小操作的个数,所以我们最后还需要将这三种情况的操作个数进行比较,取最小值作为d[i,j]的值;

d、然后重复执行3,4,5,6,最后的结果就在d[n,m]中;

图解:

step 1:初始化如下矩阵

20130607033721521.jpg?_=5632032

step 2:从源串的第一个字符(“j”)开始,从上至下与目标串进行对比

20130607033722210.jpg?_=5632032

如果两个字符相等,则在从此位置的左,上,左上三个位置中取出最小的值;若不等,则在从此位置的左,上,左上三个位置中取出最小的值再加上1;

第一次,源串第一个字符“j” 与目标串的“j”对比,左,上,左上三个位置中取出最小的值0,因为两字符相等,所以加上0;接着,依次对比“j”→“e”,“j”→“r”,“j”→“r”,,“j”→“y” 到扫描完目标串。

20130607033722541.jpg?_=5632032

step 3:遍历整个源串与目标串对比:

20130607033723500.jpg?_=5632032

20130607033723758.jpg?_=5632032

step 4:扫描完最后一列,则最后一个为最短编辑距离:

20130607033724938.jpg?_=5632032

最小编辑距离算法

package com.math;
/**
 * Created with IntelliJ IDEA.
 * Description: 编辑距离算法 又称为 Levenshtein算法
 * User: zhubo
 * Date: 2017-11-02
 * Time: 11:54
 */
public class Levenshtein {


    public static void main(String[] args) {
        String str1 = "beauty";
        String str2 = "batyu";
        System.out.println(getLevenShtein(str1,str2));
    }

    /**
     * 获取最小编辑距离静态方法
     * @param str1
     * @param str2
     * @return
     */
    public static int getLevenShtein(String str1 , String str2){
        int[][] array = initArray(str1,str2);
        for(int i= 1 ; i<= str2.length();i++){//i 是竖排
            for(int j = 1; j <= str1.length() ; j++){//j 是横排
                setValue(array,i,j,str2.charAt(i-1) == str1.charAt(j-1));
            }
        }
        printArray(array);
        return array[str2.length()][str1.length()];
    }

    /**
     *
     * @param array
     * @param i 代表纵向量
     * @param j 代表横向量
     * @param flag 代表字符是否相等
     */
    private static void setValue(int[][] array,int i , int j, boolean flag){
        int ss = array[i-1][j-1];
        int dd = array[i-1][j] +1;
        int pp = array[i][j-1] +1;
        if(flag){
            array[i][j] = getMin(ss,dd,pp);
        }else{
            array[i][j] = getMin(ss+1,dd,pp);
        }
    }

    /**
     * 求三个值中的最小值
     * @param a
     * @param b
     * @param c
     * @return
     */
    private static int getMin(int a, int b , int c){
        return Math.min(Math.min(a,b),c);
    }

    /**
     * 打印矩阵
     * @param array
     */
    private static void printArray(int[][] array){
        for(int i = 0; i < array.length;i++){
            for(int j = 0;j<array[i].length ; j++){
                System.out.print(array[i][j]+" ");
            }
            System.out.println();
        }
    }

    /**
     * 初始化矩阵
     * @param str1 横坐标代表字符串
     * @param str2 纵坐标代表字符串
     * @return
     */
    private static int[][] initArray(String str1,String str2){
        int len1 = str1.length();
        int len2 = str2.length();
        int[][] array = new int[len2+1][len1+1];
        for(int i = 0 ; i<= len1;i++){
            array[0][i] = i;
        }
        for(int i = 0 ; i<= len2 ; i++){
            array[i][0] = i;
        }
        return array;
    }
}

 

 

 

 

 

 

转载于:https://my.oschina.net/LucasZhu/blog/1559972

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值