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

↓

取最小值
相关推荐
ZhengEnCi10 小时前
GPT-6 Astra 爆改 Qwen 权重真有那么神吗:权重空间编程 0.016% 参数的真相
算法·架构
罗西的思考10 小时前
【轻量化复刻大模型 / KIMI K3】KDA(Kimi Delta Attention):并行
人工智能·算法·机器学习
夜不会漫长12 小时前
C++:红黑树
数据结构·算法
AI备案指南-满满13 小时前
算法备案审核不通过,一般是什么原因?
java·人工智能·算法·大模型备案·算法备案·大模型登记
Ramble_Naylor13 小时前
Rust深度解读:Send 与 Sync 的本质与线程安全边界
python·算法·rust
秋天的怀念_David13 小时前
算法一千零一夜 · 第二十三夜 电力民生写成的曲线
java·程序人生·算法
不一样的故事12613 小时前
NB/T 47013.8-2015 附录D 吸枪技术
人工智能·经验分享·算法
通问AI13 小时前
用 200 行 Python 给文档库做「上下文完整度」自检:四个可复算的检查项
算法
揽星河..14 小时前
【C语言】扫雷游戏
c语言·算法·游戏
丘山录14 小时前
本地部署 LongCat-2.5,要 7 台机器我只有 4 台
人工智能·算法