• 字符串编辑距离


    字符串编辑距离

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

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

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

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

    我们先以一个例子分析,比如eat变成tea。对于第一个字符,e != a,所以要想让这两个字符相等,有三种可以选择的办法

    • 修改字符,将e直接变成a,需要走1步。
    • 插入字符,在e的前面插入a,也需要走1步。
    • 删除字符,将e删除,然后比较后面的与a,也需要走1步。

    如果是 e==a,那么就可以直接跳过这个字符比较下面的字符,那么他们的距离也就是前面一步的举例了。

    经过举例子分析,很容易发现这是一个动态规划问题,那么我们就按照动态规划的一套方法来求解。

    1、维护一个dp数组,其中dp[i][j]表示s1[0]---s1[i]和s2[0]--s2[j]相同需要进行的最少步骤;

    2、边界条件初始化,dp[i][0]=i,相当于将s1挨个变成空所要进行的步数,对于dp[0][j]=j同理;

    3、状态转移方程,我们要得到dp[i][j]的值,假设s1[i-1]和s2[j-1]之前的都已经相等了,那么如果s1[i]==s2[j],显然不需要进行操作,dp[i][j]==dp[i-1][j-1];如果s1[i]!=s2[j],那么到达dp[i][j]的就有三条路,分别从dp[i-1][j-1]、dp[i-1][j]、dp[i][j-1],对应的含义分别是修改字符、删除字符和插入字符,在三种操作下,经历的步数都要+1,所以我们只要找三者的最小值然后+1就可以了。

    这个题目有一种巧妙的理解办法,就是画表格。画表格法在动态规划太有用了!!!特别是处理这种数组是二维的情况,可以直观的理解状态转移的过程,非常值得学习。

    这里以s1="cafe"  s2="coffee"。表格如下:

    (1)初始状态,这里要注意dp数组的长度要比字符串长度+1,因为要保存字符串为空的状态
          c o f f e e
                           
    c                     
    a                     
    f                     
    e                   
    (2)边界条件初始化,
          c o f f e e
       0 1 2 3 4 5 6
    c 1                  
    a 2                  
    f 3                  
    e 4                
    (3)状态转移
    我们以3,3为例,开始计算。因为c==c,所以3,3格和2,2格相同,都为0。
    对于3,4,因为c!=o,所以到达3,4格有三个方向,我们取以下三个值的最小值:
    • 对角数字+1(对于3,4来说为2)
    • 左方数字+1(对于3,4格来说为1)
    • 上方数字+1(对于3,4格来说为3)
    因此为格3,4为1
          c o f f e e
       0 1 2 3 4 5 6
    c 1 0  1             
    a 2                  
    f 3                  
    e 4                   
    循环操作,推出下表
          c o f f e e
       0 1 2 3 4 5 6
    c 1 0 1 2 3    4    5   
    a 2 1 1 2 3 4 5
    f 3 2 2 1 2 3 4
    e 4 3 3 2 2 2 3
    取右下角,得编辑距离为3
    求解字符串编辑距离方法大概就是如此,想明白之后还是挺简单的。主要还是会通过表格来找状态转移过程。
    代码如下:
     1 public void mineditdistance(){
     2         String s1 = "cafe";
     3         String s2 = "coffee";
     4         int[][] dp = new int[s1.length()+1][s2.length()+1];
     5         //对dp数组初始化
     6         for ( int i = 0 ; i < dp.length ; i ++ ) dp[i][0] = i;
     7         for ( int j = 0 ; j < dp[0].length ; j ++ ) dp[0][j] = j;
     8 
     9         for ( int i = 1 ; i < dp.length ; i ++ ){
    10             for ( int j = 1 ; j < dp[0].length; j ++ ){
    11                 if ( s1.charAt(i-1) == s2.charAt(j-1) ) dp[i][j] = dp[i-1][j-1];
    12                 else dp[i][j] = min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1;
    13             }
    14         }
    15         System.out.println(dp[dp.length-1][dp[0].length-1]);
    16     }
    17     public int min(int a, int b, int c){
    18         return Math.min(a,Math.min(b,c));
    19     }

          这个是面试时问的问题,在状态转移方程地方卡住了。回来好好又分析了一遍,颇有收获。

          字符串+极值  问题,第一个想到的就是用dp把。还有很多类似的问题,后续会慢慢总结。

          例题参考:https://blog.csdn.net/ac540101928/article/details/52786435

  • 相关阅读:
    MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用
    MVC5+EF6 入门完整教程十
    MVC5+EF6 入门完整教程九
    MVC5+EF6 入门完整教程八
    MVC5+EF6 入门完整教程七
    MVC5+EF6 入门完整教程六
    MVC5+EF6 入门完整教程五
    MVC5+EF6 入门完整教程四
    MVC5 + EF6 完整入门教程三
    从前端的UI开始
  • 原文地址:https://www.cnblogs.com/boris1221/p/9375047.html
Copyright © 2020-2023  润新知