zoukankan      html  css  js  c++  java
  • 解编辑距离问题

    编辑距离(Edit Distance),又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。
    许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。
    例如将kitten一字转成sitting:
    sitten (k→s)
    sittin (e→i)
    sitting (→g)
    俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。应用:DNA分析、拼字检查、语音辨识、抄袭侦测、相似度计算。
     
    动态规划经常被用来作为这个问题的解决手段之一。
    整数 Levenshtein距离(字符串 str1[1..m], 字符串 str2[1..n])
    //声明变量, d[i , j]用于记录str1[0...i]与str2[0..j]的Levenshtein距离
    int d[0..m, 0..n]
    //初始化
    for i from 0 to m
      d[i, 0] := i //删除i个字符
    for j from 0 to n
      d[0, j] := j //插入j个字符
    //用动态规划方法计算Levenshtein距离
    for i from 1 to m
    {
      for j from 1 to n
      {
        //计算替换操作的代价,如果两个字符相同,则替换操作代价为0,否则为1
        if str1[i]== str2[j] then cost := 0
        else cost := 1
        //d[i,j]的Levenshtein距离,可以有
        d[i, j] := minimum{
        d[i-1, j] + 1, //在str1上i位置删除字符(或者在str2上j-1位置插入字符)
        d[i, j-1] + 1, //在str1上i-1位置插入字符(或者在str2上j位置删除字符)
        d[i-1, j-1] + cost // 替换操作
        }
      } 
    }
    //返回d[m, n]
    return d[m, n]
     
     

          这篇我们看看最长公共子序列的另一个版本,求字符串相似度(编辑距离),我也说过了,这是一个非常实用的算法,在DNA对比,网

    页聚类等方面都有用武之地。

    一:概念

         对于两个字符串A和B,通过基本的增删改将字符串A改成B,或者将B改成A,在改变的过程中我们使用的最少步骤称之为“编辑距离”。

    比如如下的字符串:我们通过种种操作,痉挛之后编辑距离为3,不知道你看出来了没有?

    二:解析

      可能大家觉得有点复杂,不好理解,我们试着把这个大问题拆分掉,将"字符串 vs 字符串“,分解成”字符 vs 字符串“,再分解

    成”字符 vs 字符“。

    <1> ”字符“vs”字符“

           这种情况是最简单的了,比如”A“与”B“的编辑距离很显然是1。

    <2> ”字符”vs"字符串"

           ”A“改成”AB“的编辑距离为1,“A”与“ABA”的编辑距离为2。

    <3>“字符串”vs“字符串”

          “ABA”和“BBA”的编辑距离为1,仔细发现我们可以得出如下结论,”ABA“是由23个子序列与”BBA“字符串求的的编辑距离集

    合中取出的最小编辑距离,也就是说在这种情况下我们出现了重复计算的问题,我在求子序列”AB“和”BBA"的编辑距离时,我是由

    子序列”A“和”BBA“与”B“和”BBA“之间的编辑距离中选出一个最小值,然而序列A和序列B早之前我已经计算过了,这种重复计算

    的问题有点像”斐波那契”,正好满足“动态规划”中的最优子结构和重叠子问题,所以我们决定采用动态规划来解决。

    三:公式

        跟“最长公共子序列”一样,我们采用一个二维数组来保存字符串X和Y当前的位置的最小编辑距离。

    现有两个序列X={x1,x2,x3,...xi},Y={y1,y2,y3,....,yi},

    设一个C[i,j]: 保存Xi与Yj的当前最小的LD。

    ①: 当 X= Yi 时,则C[i,j]=C[i-1,j-1];

    ②:当 X!= Y时, 则C[i,j]=Min{C[i-1,j-1],C[i-1,j],C[i,j-1]};

    最终我们的C[i,j]一直保存着最小的LD。

    四:代码

    复制代码
     1 using System;
     2 
     3 namespace ConsoleApplication2
     4 {
     5     public class Program
     6     {
     7         static int[,] martix;
     8 
     9         static string str1 = string.Empty;
    10 
    11         static string str2 = string.Empty;
    12 
    13         static void Main(string[] args)
    14         {
    15             while (true)
    16             {
    17                 str1 = Console.ReadLine();
    18 
    19                 str2 = Console.ReadLine();
    20 
    21                 martix = new int[str1.Length + 1, str2.Length + 1];
    22 
    23                 Console.WriteLine("字符串 {0} 和 {1} 的编辑距离为:{2}
    ", str1, str2, LD());
    24             }
    25         }
    26 
    27         /// <summary>
    28         /// 计算字符串的编辑距离
    29         /// </summary>
    30         /// <returns></returns>
    31         public static int LD()
    32         {
    33             //初始化边界值(忽略计算时的边界情况)
    34             for (int i = 0; i <= str1.Length; i++)
    35             {
    36                 martix[i, 0] = i;
    37             }
    38 
    39             for (int j = 0; j <= str2.Length; j++)
    40             {
    41                 martix[0, j] = j;
    42             }
    43 
    44             //矩阵的 X 坐标
    45             for (int i = 1; i <= str1.Length; i++)
    46             {
    47                 //矩阵的 Y 坐标
    48                 for (int j = 1; j <= str2.Length; j++)
    49                 {
    50                     //相等情况
    51                     if (str1[i - 1] == str2[j - 1])
    52                     {
    53                         martix[i, j] = martix[i - 1, j - 1];
    54                     }
    55                     else
    56                     {
    57                         //取“左前方”,“上方”,“左方“的最小值
    58                         var temp1 = Math.Min(martix[i - 1, j], martix[i, j - 1]);
    59 
    60                         //获取最小值
    61                         var min = Math.Min(temp1, martix[i - 1, j - 1]);
    62 
    63                         martix[i, j] = min + 1;
    64                     }
    65                 }
    66             }
    67 
    68             //返回字符串的编辑距离
    69             return martix[str1.Length, str2.Length];
    70         }
    71     }
    72 }
    复制代码

  • 相关阅读:
    容器跨主机网络通信学习笔记(以Flannel为例)
    Kubernetes控制器Job和CronJob
    记一次使用Flannel插件排错历程
    Kubernetes控制器Deployment
    Kubernetes如何通过StatefulSet支持有状态应用?
    react18 来了,我 get 到...
    gojs 实用高级用法
    vuecli3 vue2 保留 webpack 支持 vite 成功实践
    calibre 报错 This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem. 解决
    unable to recognize "*.yaml": no matches for kind "RoleBinding" in version "rbac.authorization.k8s.io/v1beta1"
  • 原文地址:https://www.cnblogs.com/mmcmmc/p/3895538.html
Copyright © 2011-2022 走看看