动态规划一日一题-10-1-最小编辑距离


最小编辑距离


给定两个字符串 A 和 B,现在要将 A 经过若干操作变为 B,可进行的操作有:

  1. 删除–将字符串 A 中的某个字符删除。
  2. 插入–在字符串 A 的某个位置插入某个字符。
  3. 替换–将字符串 A 中的某个字符替换为另一个字符。

现在请你求出,将 A 变为 B 至少需要进行多少次操作。

输入格式

第一行包含整数 n,表示字符串 A 的长度。

第二行包含一个长度为 n 的字符串 A。

第三行包含整数 m,表示字符串 B 的长度。

第四行包含一个长度为 m 的字符串 B。

字符串中均只包含大写字母。

输出格式

输出一个整数,表示最少操作次数。

数据范围

1≤n,m≤1000

输入样例:

10 
AGTCTGACGC
11 
AGTAAGTAGGC

输出样例:

4

由dp的思想,显然需要创建一个二维的数组。

定义明确

首先明确dp数组的定义,dp[i] [j] 表示的是第一个数组的1-i转变成1-j需要的最小的操作次数(即最小的编辑距离)。

base case

该题的启动点是0-i和0-j对于第一个数组转换成第二个数组的次数是明确的。

状态转移

1.注意是从已有值转移过来的,所以设计状态方程时候需要考虑base case。

2.一般涉及字符串转换的题都有一个思路是根据双指针指到的字符相等与否来进行状态转移考虑,再结合dp数组的含义即可。

代码

#include 

using namespace std ;

const int N = 10010 ;

int f[N][N] ;

char p[N] ,q[N] ;
int main()
{
    
    int n , m  ; 
    scanf("%d%s",&n , p+1) ;    //这有一个小技巧,当涉及字符串的读入的时候,尽量使用%s,防止空格的读入
    scanf("%d%s",&m , q+1) ;
    
    //base case
    
    for(int i = 1 ; i <= n ;++i)
    {
        f[i][0] = i ; 
    }
    for(int j = 1 ; j <= m ;++j)
    {
        f[0][j] = j ;
    }
    
    //状态转移
    
    for(int i = 1 ; i <= n ;++i)
    {
        for(int j = 1 ; j <= m ;++j)
        {
            f[i][j] = min(f[i-1][j] , f[i][j-1]) ; //之前我一直在想这一步的必要性,后来其实是如果不写的话,后面的转移就直接没有值
            if(p[i] == q[j])
            {
                f[i][j] = min(f[i][j] , f[i-1][j-1]) ;
            }
            else
            {
                f[i][j] = min(f[i][j] , f[i-1][j-1] + 1) ;
            }
        }
    }
    
    cout << f[n][m] << endl ;
       return 0 ; 
}

文章作者: 罗林
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 罗林 !
  目录