动态规划经典例子——编辑距离问题

Posted texas

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划经典例子——编辑距离问题相关的知识,希望对你有一定的参考价值。

问题描述:

  两个字符串,一个是起点字符串,另一个是终点。

  例如,起点字符串ddl到终点字符串de的转换步骤如下:

  ddl->del->def。

  编辑距离为2。

算法分析:

  首先考虑上面例子中ddl的第一个字符和def的第一个字符,们是一样的,所以只需要计算a[2...lengthA]和b[2...lengthB](dl和ef)之间的距离即可。

  若两个字符串的第一个字符不同,例如adl和def,可以三选一:

  • 把终点串的第一个字符插入到起点串的第一个字符之前(adl->dadl),然后计算a[1...lengthA]和b[2...lengthB](dadl和def)的距离即可;
  • 删除起点串的第一个字符(adl->dl),然后计算a[2...lengthA]和b[1...lengthB](dl->def)的距离即可;
  • 修改起点串的第一个字符成终点串的第一个字符(adl->ddl),然后计算a[2...lengthA]和b[2...lengthB](dl和ef)的距离即可。

  考虑起点串的第i个字符和终点串的第j个字符的话也是一样的。

当不考虑起点串的前i-1字符和终点串的前j-1个字符,如果起点串的第i个字符和终点串的第j个字符相等,即a[i-1] = b[j-1],则只需要计算a[i...lengthA]和b[j...lengthB]之间的距离即可。

  如果不相等,可以三选一:

  • 把终点串的第j个字符插入到起点串的第i个字符之前,然后计算a[i...lengthA]和b[j+1...lengthB]的距离即可;
  • 删除起点串的第i个字符,然后计算a[i+1...lengthA]和b[j...lengthB]的距离即可;
  • 修改起点串的第i个字符成终点串的第j个字符,之然后计算a[i+1...lengthA]和b[j+1...lengthB]的距离即可;

     那么进行三选一的依据是什么呢?是起点串的前i-1字符和终点串的前j-1个字符的编辑距离。

  递归方程:

技术图片

 

 

 

  edit[i-1][j]+1相当于给起点串的最后插入了终点串的最后的字符,插入操作使得edit+1,之后计算edit[i-1][j];

  edit[i][j-1]+1相当于将起点串的最后字符删除,删除操作edit+1,之后计算edit[i][j-1];

  edit[i-1][j-1]+flag相当于通过将起点串的最后一个字符替换为终点串的最后一个字符。若a[i-1] = b[j-1],flag = 0;若a[i-1] != b[j-1],flag = 1。

  

技术图片
#include<iostream>
#include<string.h>
using namespace std;


int main() {
    char a[2000], b[2000];

    cin.getline((a+1), 2001);
    cin.getline((b+1), 2001);
    
    int lengthA = strlen(a) - 1;
    int lengthB = strlen(b) - 1 ;
    
    int editDistance[2001][2001];
    editDistance[0][0] = 0;
    
    for(int i = 1; i <= lengthA; i++) {
        editDistance[i][0] = i;
    }
    for(int i = 1; i <= lengthB; i++) {
        editDistance[0][i] = i;
    }
    for(int i = 1; i <= lengthA; i++)
        for(int j = 1; j <= lengthB; j++) {
            if(a[i] == b[j]) {
                editDistance[i][j] = editDistance[i-1][j-1];
            }
            else {
                editDistance[i][j] = min(editDistance[i-1][j], min(editDistance[i][j-1], editDistance[i-1][j-1])) + 1;
            }
        }
    
    cout << editDistance[lengthA][lengthB];
    
    return 0;
}
View Code

复杂度分析

  时间复杂度:O(m*n)

  空间复杂度:O(1)

心得

递归方程很重要。

以上是关于动态规划经典例子——编辑距离问题的主要内容,如果未能解决你的问题,请参考以下文章

经典动态规划:编辑距离

经动态规划:编辑距离

Leetcode 动态规划刷题总结

简言翻译记忆的原理:用动态规划算法求解最短编辑距离

动态规划2最大子段和,编辑距离,括号匹配问题...

动态规划经典教学题,上过《算导》的应该都会