• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
最短编辑距离-线性dp模板题

题目

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

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

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

输入格式

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

第二行包含一个长度为 nn 的字符串 AA。

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

第四行包含一个长度为 mm 的字符串 BB。

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

输出格式

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

数据范围

1≤n,m≤10001≤n,m≤1000

输入样例:

10 
AGTCTGACGC
11 
AGTAAGTAGGC

输出样例:

4

思路 dp

​ 这题一开始想的时候是BFS枚举所有状态,但是插入就有点麻烦了,因为位置不确定,所以这样暴力就很难想了。 没想到这种题也可以有dp,确实dp能够应用到任何可以进行状态转移的地方。和最长公共子序列很相似。

​ 设\(dp[i][j]\)表示字符\(a\)的前\(i\)个字符和字符\(b\)的前\(j\)个字符匹配所需的最小操作数,不考虑前\(i,j\)个字符,可以肯定这种状态是无后效性的,即前面做出的改变并不会影响后面的状态递推。

​ 我们假设\(a[i] != b[j]\), 若\(a\)和\(b\)若进行删除操作则之前的状态为\(f[i - 1][j]\),若执行插入操作则之前的状态为\(f[i - 1][j]\), 若执行替换操作则之前的状态为\(f[i - 1][j - 1]\)

​ \(dp[i][j]=max(dp[i - 1][j] + 1, dp[i - 1][j] + 1, dp[i - 1][j - 1] + (int)(a[i] == a[j]))\)

Code

#include <iostream>

using namespace std;

char a[1010], b[1010];

int dp[1010][1010];
// dp[i][j]表示对于考虑串a的前i个字符和串b的前j个字符的最小操作数

int main() {
    int n, m;
    
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    cin >> m;
    for(int i = 1; i <= m; i ++) cin >> b[i];
    
    for(int i = 1; i <= n; i ++) dp[i][0] = i;
    for(int i = 1; i <= m; i ++) dp[0][i] = i;
    for(int i = 1; i <= n; i ++) {
        for(int j = 1; j <= m; j ++) {
            dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1;
            dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + (int)(a[i] != b[j]));
        }
    }
    cout << dp[n][m] << "\n";
}
posted on 2023-01-13 21:30  Jack404  阅读(16)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3