字符串线性DP-洛-编辑距离

P2758 编辑距离

题目描述

设 \(A\) 和 \(B\) 是两个字符串。我们要用最少的字符操作次数,将字符串 \(A\) 转换为字符串 \(B\)。这里所说的字符操作共有三种:

  1. 删除一个字符;
  2. 插入一个字符;
  3. 将一个字符改为另一个字符。

\(A, B\) 均只包含小写字母。

输入格式

第一行为字符串 \(A\);第二行为字符串 \(B\);字符串 \(A, B\) 的长度均小于 \(2000\)。

输出格式

只有一个正整数,为最少字符操作次数。

输入输出样例 #1

输入 #1

sfdqxbw
gfdgw

输出 #1

4

说明/提示

对于 \(100 \%\) 的数据,\(1 \le |A|, |B| \le 2000\)。

思路

其实一开始dp数组的想法大致正确,只是状态转移方程不知道怎么写。不要真想着改变字符串,只是想着处理到某个位置用什么操作,是怎么得到的。不要想着破坏a的结构,否则要存很多中间状态,很复杂,只需省略中间,保存结果。但是要注意初始化,这样可以省去好多为0的特判。
转移方程:
1.删除:删掉 A [i] → dp[i-1][j] + 1 2.插入:在 A 末尾补上 B [j] → dp[i][j-1] + 1
3.替换:如果 A[i]==B[j]:不用改 → dp[i-1][j-1]; 如果不等:需要修改一次 → dp[i-1][j-1] + 1
删是看a自己前面的,增是看b前面的是否满足。
代码;

点击查看代码
#include <bits/stdc++.h>
using namespace std;
string a,b;
int dp[2010][2010];    //处理a前i个字符得到b前j个字符
int main()
{
    cin>>a>>b;
    memset(dp,0x3f,sizeof(dp));
    for(int i = 0;i <= b.size();i++)    dp[0][i] = i;    //增,处理i=0
    for(int i = 0;i <= a.size();i++)    dp[i][0] = i;    //删,处理j=0
    for(int i = 1;i <= a.size();i++)
    {
        for(int j = 1;j <= b.size();j++)
        {
            //1.删
            dp[i][j] = min(dp[i][j],dp[i-1][j] + 1);
            //2.增
            dp[i][j] = min(dp[i][j],dp[i][j-1] + 1);
            //3.改
            if(a[i-1] == b[j-1])     dp[i][j] = min(dp[i][j],dp[i-1][j-1]);    //下标注意一定要减1
            else dp[i][j] = min(dp[i][j],dp[i-1][j-1]+1);
        }
    }
    //cout<<dp[1][1]<<endl;
    cout<<dp[a.size()][b.size()];
    return 0;
}
posted @ 2026-08-13 13:09  lucky_lh  阅读(11)  评论(0)    收藏  举报