zoukankan      html  css  js  c++  java
  • 算法之美--3.3.1 全局编辑距离

    编辑距离概念描述:

    编辑距离,又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。

    例如将kitten一字转成sitting:

    1. sitten (k→s)
    2. sittin (e→i)
    3. sitting (→g)

    俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。

    问题:找出字符串的编辑距离,即把一个字符串s1最少经过多少步操作变成编程字符串s2,操作有三种,添加一个字符,删除一个字符,修改一个字符

    解析:

    该算法和书本上的德勒曼-温施算法思路一样。

    首先定义这样一个函数——edit(i, j),它表示第一个字符串的长度为i的子串到第二个字符串的长度为j的子串的编辑距离。

    显然可以有如下动态规划公式:

    • if i == 0 且 j == 0,edit(i, j) = 0
    • if i == 0 且 j > 0,edit(i, j) = j
    • if i > 0 且j == 0,edit(i, j) = i
    • if i ≥ 1  且 j ≥ 1 ,edit(i, j) == min{ edit(i-1, j) + 1, edit(i, j-1) + 1, edit(i-1, j-1) + f(i, j) },当第一个字符串的第i个字符不等于第二个字符串的第j个字符时,f(i, j) = 1;否则,f(i, j) = 0。
      0 f a i l i n g
    0                
    s                
    a                
    i                
    l                
    n                
      0 f a i l i n g
    0 0 1 2 3 4 5 6 7
    s 1              
    a 2              
    i 3              
    l 4              
    n 5              

     计算edit(1, 1),edit(0, 1) + 1 == 2,edit(1, 0) + 1 == 2,edit(0, 0) + f(1, 1) == 0 + 1 == 1,min(edit(0, 1),edit(1, 0),edit(0, 0) + f(1, 1))==1,因此edit(1, 1) == 1。 依次类推:

      0 f a i l i n g
    0 0 1 2 3 4 5 6 7
    s 1 1 2 3 4 5 6 7
    a 2 2            
    i 3              
    l 4              
    n 5              

    edit(2, 1) + 1 == 3,edit(1, 2) + 1 == 3,edit(1, 1) + f(2, 2) == 1 + 0 == 1,其中s1[2] == 'a' 而 s2[1] == 'f'‘,两者不相同,所以交换相邻字符的操作不计入比较最小数中计算。以此计算,得出最后矩阵为:

      0 f a i l i n g
    0 0 1 2 3 4 5 6 7
    s 1 1 2 3 4 5 6 7
    a 2 2 1 2 3 4 5 6
    i 3 3 2 1 2 3 4 5
    l 4 4 3 2 1 2 3 4
    n 5 5 4 3 2 2 2 3

     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 int min(int a, int b)
     7 {
     8     return a < b ? a : b;
     9 }
    10 
    11 int edit(string str1, string str2)
    12 {
    13     int max1 = str1.size();
    14     int max2 = str2.size();
    15 
    16     int **ptr = new int*[max1 + 1];
    17     for(int i = 0; i < max1 + 1 ;i++)
    18     {
    19         ptr[i] = new int[max2 + 1];
    20     }
    21 
    22     for(int i = 0 ;i < max1 + 1 ;i++)
    23     {
    24         ptr[i][0] = i;
    25     }
    26 
    27     for(int i = 0 ;i < max2 + 1;i++)
    28     {
    29         ptr[0][i] = i;
    30     }
    31 
    32     for(int i = 1 ;i < max1 + 1 ;i++)
    33     {
    34         for(int j = 1 ;j< max2 + 1; j++)
    35         {
    36             int d;
    37             int temp = min(ptr[i-1][j] + 1, ptr[i][j-1] + 1);
    38             if(str1[i-1] == str2[j-1])
    39             {
    40                 d = 0 ;
    41             }
    42             else
    43             {
    44                 d = 1 ;
    45             }
    46             ptr[i][j] = min(temp, ptr[i-1][j-1] + d);
    47         }
    48     }
    49 
    50     cout << "**************************" << endl;
    51     for(int i = 0 ;i < max1 + 1 ;i++)
    52     {
    53         for(int j = 0; j< max2 + 1; j++)
    54         {
    55             cout << ptr[i][j] << " " ;
    56         }
    57         cout << endl;
    58     }
    59     cout << "**************************" << endl;
    60     int dis = ptr[max1][max2];
    61 
    62     for(int i = 0; i < max1 + 1; i++)
    63     {
    64         delete[] ptr[i];
    65         ptr[i] = NULL;
    66     }
    67 
    68     delete[] ptr;
    69     ptr = NULL;
    70 
    71     return dis;
    72 }
    73 
    74 int main(void)
    75 {
    76     string str1 = "sailn";
    77     string str2 = "failing";
    78 
    79     int r = edit(str1, str2);
    80     cout << "the dis is : " << r << endl;
    81 
    82     return 0;
    83 }

    C版:

    #include<stdio.h>
    #include <string.h>
    #include <malloc.h>
    
    void backtracking(int**, char*, char*);    //回溯,计算出如何通过其中一个字符串的变换,得到另外一个字体串
    int ** build_matrix(char*, char*);         //求编辑距离,返回一个已经填充好的矩阵
    int trigle_min(int a, int b, int c);       //求三个数的最小值
    
    
    int main()
    {
        char* A = "GGATCGA";
        char* B = "GAATTCAGTTA";
        int** matrix = build_matrix(A, B);
        printf("A和B的编辑距离为:%d
    ", matrix[strlen(A)][strlen(B)]);
        backtracking(matrix, A, B);
        return 0;
    }
    
    //0 左上角 ,1上方,-1左边
    int way(int i_t, int j_t, int i, int j)
    {
        if (i - i_t == 1 && j - j_t == 1) {
            return 0;
        }
        if (i - i_t == 1 && j - j_t == 0) {
            return 1;
        }
        if (i - i_t == 0 && j - j_t == 1) {
            return -1;
        }
    }
    
    int** build_matrix(char* A, char* B)
    {
        int m = strlen(A);
        int n = strlen(B);
        int** matrix = (int**)malloc(sizeof(int*)*(m + 1));
        int i, j;
        for (i = 0; i < m + 1; i++)
        {
            *(matrix + i) = (int*)malloc(sizeof(int)*(n + 1));
        }
        matrix[0][0] = 0;
        for (i = 1; i < n + 1; i++)
        {
            matrix[0][i] = i;
        }
        for (i = 1; i < m + 1; i++)
        {
            matrix[i][0] = i;
        }
    
        for (i = 1; i < m + 1; i++)
        {
            for (j = 1; j < n + 1; j++)
            {
                if (*(A + i - 1) == *(B + j - 1))
                {
                    matrix[i][j] = matrix[i - 1][j - 1];
                }
                else
                {
                    matrix[i][j] = trigle_min(matrix[i - 1][j], matrix[i][j - 1], matrix[i - 1][j - 1]) + 1;
                }
            }
        }
        for (i = 0; i <= m; i++)
        {
            for (j = 0; j <= n; j++)
            {
                printf("%d ", matrix[i][j]);
            }
            printf("
    ");
        }
        return matrix;
    }
    
    void backtracking(int** matrix, char* A, char *B) {
        int m = strlen(A);
        int n = strlen(B);
        int i = m;
        int j = n;
        int max = m > n ? m : n;
        char* p = (char*)malloc(sizeof(char)*m);
        char* q = (char*)malloc(sizeof(char)*m);
        int k = 0;
        while (i > 0 && j > 0)
        {
            if (*(A + i - 1) == *(B + j - 1))
            {
                *(p + k) = *(A + i - 1);
                *(q + k) = *(B + j - 1);
                --i;
                --j;
                ++k;
            }
            else
            {
                int i_t = 0;
                int j_t = 0;
                if (matrix[i][j - 1] >= matrix[i - 1][j])
                {
                    i_t = i - 1;
                    j_t = j;
                }
                else {
                    i_t = i;
                    j_t = j - 1;
                }
                if (matrix[i_t][j_t] >= matrix[i - 1][j - 1])
                {
                    i_t = i - 1;
                    j_t = j - 1;
                }
                /////////      
                int w = way(i_t, j_t, i, j);
                if (w == 0)  {
                    *(p + k) = *(A + i - 1);
                    *(q + k) = *(B + j - 1);
                }
                else if (w == -1) {
                    *(p + k) = '-';
                    *(q + k) = *(B + j - 1);
                }
                else {
                    *(p + k) = *(A + i - 1);
                    *(q + k) = '-';
                }
                ++k;
                i = i_t;
                j = j_t;
            }
        }
        if (i == 0) {
            *(q + k) = *(B + j - 1);
            *(q + k) = '-';
    
        }
        else {
            *(p + k) = *(A + i - 1);
            *(q + k) = '-';
    
        }
        for (i = max - 1; i >= 0; i--) {
            printf("%c", *(p + i));
        }
        printf("
    ");
        for (i = max - 1; i >= 0; i--) {
            printf("%c", *(q + i));
        }
    }
    
    int trigle_min(int a, int b, int c)
    {
        int min = a < b ? a : b;
        return min < c ? min : c;
    }

    reference:编辑距离及编辑距离算法

                       编辑距离算法(LD)详解

  • 相关阅读:
    【Java EE 学习 81】【CXF框架】【CXF整合Spring】
    【Java EE 学习 80 下】【调用WebService服务的四种方式】【WebService中的注解】
    【Java EE 学习 80 上】【WebService】
    【Java EE 学习 79 下】【动态SQL】【mybatis和spring的整合】
    【Java EE 学习 79 上】【mybatis 基本使用方法】
    【Java EE 学习 78 下】【数据采集系统第十天】【数据采集系统完成】
    【Java EE 学习 78 中】【数据采集系统第十天】【Spring远程调用】
    【Java EE 学习 78 上】【数据采集系统第十天】【Service使用Spring缓存模块】
    【Java EE 学习 77 下】【数据采集系统第九天】【使用spring实现答案水平分库】【未解决问题:分库查询问题】
    【Java EE 学习 77 上】【数据采集系统第九天】【通过AOP实现日志管理】【通过Spring石英调度动态生成日志表】【日志分表和查询】
  • 原文地址:https://www.cnblogs.com/ranjiewen/p/6395241.html
Copyright © 2011-2022 走看看