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

↓

取最小值
相关推荐
李可以量化1 小时前
Tornado 从了解到精通(四)上:实战搭建 Web 应用与核心组件详解
算法
linux-hzh2 小时前
百日算法修炼 · Day 09
数据结构·算法·排序算法
DFT计算杂谈2 小时前
Janus单层Cr2SSe中的应变可调多压电效应与谷电子学
人工智能·算法·机器学习
今天AI了吗2 小时前
从 LLM 到 Agent Skill:把 AI 底层概念串起来
数据库·人工智能·sql·深度学习·神经网络·算法·机器学习
hanlin032 小时前
动态规划专练:力扣第1035、392题
算法·leetcode·动态规划
不正经学生3 小时前
C语言大小端字节序:内存里字节的排列顺序
c语言·开发语言·arm开发·c++·算法·c#
大模型探索者3 小时前
2026金融大模型训推平台选型指南:主流厂商横向对比与私有化落地
人工智能·算法·金融
依然鸣4 小时前
PTA团体程序设计天梯赛L2真题讲解L2-001-004
经验分享·学习·算法·深度优先·pat考试
杨航 AI5 小时前
** AI 面试算法 50 题清单**,不是单纯的 LeetCode 题号列表,而是按照“**考察概率 × 面试价值 × 你当前准备方向**”排序
算法·leetcode·面试