P2758 编辑距离 题解复盘

P2758 编辑距离 题解复盘

类型:字符串DP(编辑距离)

目标:将字符串 A 转换为字符串 B,使操作次数最少。


基本信息

项目 内容
题目编号、来源 P2758 洛谷
训练层级 B普及
知识版块 字符串DP、编辑距离、二维DP

解题前・关键信号识别

维度 分析
目标、约束、底层结构 将字符串 A 转换成字符串 B,允许删除、插入、修改三种操作,求最少操作次数。
数据规模 字符串长度 ≤2000,需要 O(n²) 算法。
候选算法和依据 每个状态都与两个字符串的前缀有关,使用二维DP。
复杂度预判 时间复杂度:O(nm) 空间复杂度:O(nm)

解题后・外化复盘

维度 内容
状态定义 dp[i][j] 表示:将字符串 A 的前 i 个字符转换成字符串 B 的前 j 个字符所需要的最少操作次数。
状态转移 a[i-1]==b[j-1]dp[i][j]=dp[i-1][j-1] 否则: dp[i][j]=min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+1)
遍历顺序 按 i、j 正序遍历,因为每个状态依赖左、上、左上三个状态。
实现结构 / 核心思路 ① 初始化第一行、第一列。 ② 双重循环枚举两个字符串前缀。 ③ 相同字符直接继承。 ④ 不同字符枚举删除、插入、修改三种操作。
错因回溯 ① 一开始倒序遍历,状态依赖方向错误。 ② 使用 a[i]b[j],导致字符串越界,正确应使用 a[i-1]b[j-1]。 ③ 初始化后仍从 (0,0) 开始更新,导致访问 dp[-1][*]
边界和易错点 1. dp[i][0]=i(删除 i 次)。 2. dp[0][j]=j(插入 j 次)。 3. DP 从 (1,1) 开始。 4. 字符比较使用 a[i-1]b[j-1]
下次看到什么信号,我应该想到这个方法 看到: ① 字符串转换 ② 删除、插入、修改 ③ 求最少操作次数 想到:编辑距离(二维DP)

三种操作理解

假设:

text 复制代码
A → B

始终是在修改第一个字符串 A

删除

例如:

text 复制代码
abc

↓

ac

删除:

text 复制代码
b

对应:

cpp 复制代码
dp[i-1][j]+1

插入

例如:

text 复制代码
ab

↓

abc

插入:

text 复制代码
c

对应:

cpp 复制代码
dp[i][j-1]+1

修改

例如:

text 复制代码
cat

↓

cut

修改:

text 复制代码
a

↓

u

对应:

cpp 复制代码
dp[i-1][j-1]+1

为什么这样初始化?

第一列

例如:

text 复制代码
abc

↓

空串

只能:

text 复制代码
删除3次

所以:

cpp 复制代码
dp[3][0]=3;

即:

cpp 复制代码
dp[i][0]=i;

第一行

例如:

text 复制代码
空串

↓

abc

只能:

text 复制代码
插入3次

所以:

cpp 复制代码
dp[0][3]=3;

即:

cpp 复制代码
dp[0][j]=j;

为什么字符相同不用操作?

例如:

text 复制代码
abc

abc

最后一个字符:

text 复制代码
c
c

已经相同。

因此:

不用修改。

直接:

cpp 复制代码
dp[i][j]=dp[i-1][j-1];

AC完整代码

cpp 复制代码
#include<iostream>
#include<algorithm>
using namespace std;

int dp[2005][2005];

int main()
{
    string a,b;
    cin>>a>>b;

    int len1=a.size();
    int len2=b.size();

    for(int i=0;i<=len1;i++)
        dp[i][0]=i;

    for(int j=0;j<=len2;j++)
        dp[0][j]=j;

    for(int i=1;i<=len1;i++)
    {
        for(int j=1;j<=len2;j++)
        {
            if(a[i-1]==b[j-1])
            {
                dp[i][j]=dp[i-1][j-1];
            }
            else
            {
                dp[i][j]=min(
                    dp[i-1][j]+1,
                    min(
                        dp[i][j-1]+1,
                        dp[i-1][j-1]+1
                    )
                );
            }
        }
    }

    cout<<dp[len1][len2];

    return 0;
}

模型总结

模型 状态 转移
LCS dp[i][j] max()
编辑距离 dp[i][j] min()
路径DP dp[i][j] 从相邻位置转移
区间DP dp[l][r] 从左右区间转移

LCS 与 编辑距离 对比

内容 LCS 编辑距离
求什么 最长公共子序列长度 最少操作次数
字符相同 +1 不加
字符不同 max() min()
初始化 全部为0 第一行、第一列分别为0~n
状态 前缀最长公共子序列 前缀最少编辑次数

记忆

text 复制代码
看到:

① 字符串转换

② 删除

③ 插入

④ 修改

⑤ 求最少操作次数

↓

想到:

编辑距离

状态:

dp[i][j]

↓

字符相同:

dp[i-1][j-1]

↓

字符不同:

删除:

dp[i-1][j]+1

插入:

dp[i][j-1]+1

修改:

dp[i-1][j-1]+1

↓

取最小值
相关推荐
靠沿26 分钟前
贪心算法专题(三)
算法·贪心算法
super大力张1 小时前
MOE基于结构的药物设计(七):Ligand R-Vectors——如何判断配体可以从哪里继续生长?
数据库·算法·cadd·moe·svl·基于结构的药物设计
Tongsr2 小时前
别只混淆代码:用 Kaleido 加固整个 Android Release AAB
前端·算法·github
高亦真2 小时前
今天是学习嵌入式的第34天
linux·学习·算法
飞Link3 小时前
动作方法中的分割与过度分割方法全解析(含代码实战与踩坑案例)
人工智能·python·算法·计算机视觉
张宇Joaquin3 小时前
鲲鹏统一并行加速库KUPL--异步数据拷贝
线性代数·算法·矩阵·numpy
GlobalInfo3 小时前
创新不是追逐热点,是在变化中建立长期竞争力
大数据·算法
lvwangshu4 小时前
线性代数基础 Linear Algebra Basics
数学·算法
ZhouDevin4 小时前
算法论文/数据集5——AlignPrune(CVPR2026)基于样本损失时间序列精确识别噪声样本
算法
十铭忘5 小时前
HMM(隐马尔可夫模型)的理解7——Baum–Welch 算法
人工智能·算法