news 2026/6/1 12:31:21

编辑距离(Edit Distance)——从字符串相似度到动态规划经典模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
编辑距离(Edit Distance)——从字符串相似度到动态规划经典模型

引言

在自然语言处理(NLP)、搜索引擎纠错、DNA序列比对、拼写检查系统等领域,经常需要衡量两个字符串之间的相似程度。

例如:

kitten sitting

显然两个单词非常接近,但究竟有多接近?

如何用数学方法描述这种“接近程度”?

为了解决这一问题,俄罗斯科学家 Vladimir Levenshtein 于 1965 年提出了著名的Levenshtein Distance(编辑距离)

编辑距离定义为:

将一个字符串转换为另一个字符串所需要执行的最少编辑操作次数。

允许的操作包括:

  • 插入(Insert)

  • 删除(Delete)

  • 替换(Replace)


问题描述

给定两个字符串:

word1 word2

求将word1转换为word2所需的最少操作次数。

例如:

horse → ros

转换过程:

horse ↓ replace(h,r) rorse ↓ delete(r) rose ↓ delete(e) ros

答案:

3

编辑距离的本质

假设:

word1 = horse word2 = ros

我们关注的是:

horse前i个字符 与 ros前j个字符

之间的最优转换方案。

因此可以发现:

一个大问题可以分解为若干个更小的子问题。

这正是动态规划的典型特征。


动态规划状态定义

设:

dp[i][j]

表示:

word1前i个字符 转换成 word2前j个字符 所需的最少操作次数

例如:

dp[3][2]

表示:

"hor" → "ro"

的最小编辑距离。


状态转移推导

这是整道题最核心的部分。


情况一:字符相同

假设:

word1[i-1] == word2[j-1]

例如:

abc abc

最后一个字符已经匹配:

c == c

无需额外操作。

因此:

dp[i][j] = dp[i-1][j-1]

情况二:字符不同

假设:

word1[i-1] != word2[j-1]

例如:

horse ros

最后一个字符不同。

此时有三种选择。


1. 删除

删除 word1 的最后一个字符:

horse ↓ hors

问题变成:

dp[i-1][j]

再加一次删除操作:

dp[i-1][j] + 1

2. 插入

向 word1 末尾插入一个字符:

hors ↓ horse

对应:

dp[i][j-1]

再执行一次插入:

dp[i][j-1] + 1

3. 替换

直接修改最后一个字符:

horse ↓ rorse

对应:

dp[i-1][j-1]

加一次替换:

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

综合状态转移方程

因此得到:

dp[i][j]=\min\left(dp[i-1][j]+1,\ dp[i][j-1]+1,\ dp[i-1][j-1]+cost\right)

其中:

cost = 0 (字符相同) 1 (字符不同)

或者写成:

if(word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1]; else dp[i][j] = min({ dp[i-1][j], // 删除 dp[i][j-1], // 插入 dp[i-1][j-1] // 替换 }) + 1;

初始化分析

动态规划中最容易忽略的部分就是边界条件。


第一列

dp[i][0]

表示:

word1前i个字符 → 空串

唯一办法:

全部删除

因此:

dp[i][0] = i;

第一行

dp[0][j]

表示:

空串 → word2前j个字符

只能不断插入:

dp[0][j] = j;

DP表格演示

以:

word1 = horse word2 = ros

为例:

""ros
""0123
h1123
o2212
r3222
s4332
e5443

最终:

dp[5][3]

即:

3

代码实现

class Solution { public: int minDistance(string word1, string word2) { int m = word1.size(); int n = word2.size(); vector<vector<int>> dp( m + 1, vector<int>(n + 1, 0) ); // 初始化 for(int i = 0; i <= m; i++) dp[i][0] = i; for(int j = 0; j <= n; j++) dp[0][j] = j; // 状态转移 for(int i = 1; i <= m; i++) { for(int j = 1; j <= n; j++) { if(word1[i-1] == word2[j-1]) { dp[i][j] = dp[i-1][j-1]; } else { dp[i][j] = min({ dp[i-1][j], // 删除 dp[i][j-1], // 插入 dp[i-1][j-1] // 替换 }) + 1; } } } return dp[m][n]; } };

空间优化

观察状态转移:

dp[i][j]

仅依赖于:

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

即:

  • 当前行

  • 上一行

因此可以压缩成:

O(n)

空间复杂度。

优化后:

时间复杂度:O(mn) 空间复杂度:O(n)

编辑距离的现实应用

编辑距离远不止是一道算法题。

它广泛应用于工业系统。


搜索引擎纠错

用户输入:

googel

系统自动纠正:

google

因为:

EditDistance(googel, google)=2

拼写检查器

例如:

  • Microsoft Word

  • VSCode

  • IntelliJ IDEA

都会计算候选词的编辑距离。


DNA序列比对

生物信息学中:

ACTGCA ACTACA

可以通过编辑距离衡量基因序列相似度。


OCR文字识别

识别结果:

ChatGP7

真实结果:

ChatGPT

编辑距离:

1

系统可以自动修正。


动态规划思想总结

编辑距离是动态规划中的经典代表问题,其核心思想可以概括为:

  1. 将字符串问题转化为二维状态空间。

  2. 定义dp[i][j]表示两个前缀字符串的最优解。

  3. 根据最后一个字符是否相同进行分类讨论。

  4. 将复杂转换过程归结为:

    • 插入

    • 删除

    • 替换

最终建立最优子结构关系。

从算法体系角度看,编辑距离与:

  • 最长公共子序列(LCS)

  • 最长公共子串

  • 不同的子序列

  • 正则表达式匹配

共同构成了字符串动态规划(String DP)的重要基础,其思想在自然语言处理、生物信息学以及搜索推荐系统中均具有广泛应用价值。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/1 12:30:35

拆分APK安装难题?SAI为你提供终极解决方案

拆分APK安装难题&#xff1f;SAI为你提供终极解决方案 【免费下载链接】SAI Android split APKs installer 项目地址: https://gitcode.com/gh_mirrors/sa/SAI 还在为无法安装拆分APK文件而烦恼吗&#xff1f;当你在Android设备上遇到那些神秘的.xapk、.apks或.apkm文件…

作者头像 李华
网站建设 2026/6/1 12:29:47

基于Arduino与红外遥控的四通道家庭自动化系统DIY指南

1. 项目概述与核心思路作为一个玩了十多年电子DIY的老玩家&#xff0c;我始终觉得&#xff0c;家庭自动化最迷人的地方不在于它有多“智能”&#xff0c;而在于它能把一个抽象的控制想法&#xff0c;通过自己的双手&#xff0c;变成看得见、摸得着的物理现实。今天要聊的这个“…

作者头像 李华
网站建设 2026/6/1 12:29:09

工业相机参数看着都简单,真到现场最容易翻车的是这 5 个

很多人第一次拿到工业相机&#xff0c;先看的都是分辨率。 像素高一点&#xff0c;听起来就更专业&#xff1b;参数表长一点&#xff0c;感觉就更能打。可真到项目现场&#xff0c;先出问题的往往不是算法&#xff0c;而是你一开始就把参数看偏了。 工业相机最容易被误解的地方…

作者头像 李华
网站建设 2026/6/1 12:29:09

【C++】 —— 笔试刷题day_17

一、小乐乐改数字 题目解析 这道题&#xff0c;它们给定一个数&#xff0c;我们要对它进行修改&#xff1b;如果某一位是奇数&#xff0c;就把它变成1,&#xff1b;如果是偶数&#xff0c;就把它变成0&#xff1b; 让我们输出最后得到的数。 算法思路 这道题&#xff0c;总体…

作者头像 李华
网站建设 2026/6/1 12:25:49

18.Web API 实战:元素与表单属性的获取和修改

目录 一、获取/修改元素属性 1. 图片元素属性操作示例 2. 输入框与图片的交互示例 二、获取/修改表单元素属性 1. 代码示例&#xff1a;切换按钮的文本 2. 代码示例&#xff1a;点击计数 3. 代码示例&#xff1a;全选/取消全选按钮 一、获取/修改元素属性 可以通过 Elem…

作者头像 李华
网站建设 2026/6/1 12:25:49

WandEnhancer:解锁WeMod完整功能的开源增强方案

WandEnhancer&#xff1a;解锁WeMod完整功能的开源增强方案 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/gh_mirrors/we/Wand-Enhancer 你是否厌倦了游戏修改器繁琐的付费订阅&…

作者头像 李华