0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

彻底理解编辑距离问题edit distance

算法与数据结构 来源:码农的荒岛求生 2023-04-10 14:04 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

给定两个字符串word1以及word2,返回将word1转为word2需要的最少步骤,在每一步中你可以针对字符串word1进行以下操作:

新增一个字符

删除一个字符

替换一个字符

假如word1是"horse",word2是“ros”,那么你的程序需要返回3,也就是说将word1转为word2至少需要三个步骤:

将word1中的第一个字符h替换为字符r:horse -> rorse,此时word1变为rorse,word1与word2前两个字符相等

将word1中的第三个字符r删掉:rorse -> rose,此时word1变为rose,word1与word2的前三个字符相等

将word1中的最后一个字符删掉:rose -> ros,此时word1与word2相等。

想一想该怎样用动态规划解决这个问题。

选择与子问题

和之前的题目一样,你首先应该找出子问题是什么,子问题与原始问题的依赖关系是什么。

找出子问题的关键在于每一步的选择。

如果word1与word2的第一个字符相等,假设word1是hor、word2是hr,那么我们可以放心的排除掉两个字符串的第一个字符,即EditDistance("hor", "hr")一定等于EditDistance("or", "r"):

4c0324f2-d75a-11ed-bfe3-dac502259ad0.png

此时我们得到了一个子问题EditDistance("or", "r"),原始问题EditDistance("hor", "hr")的值等于该子问题。

真正有趣的是如果word1与word2的第一个字符不相等的情况,假设word1为“hor”,而word2为“ro”,此时根据该问题的规则针对word1的第一个字符有三种操作:

1,在word1的第一个字符前新增(Insert)一个字符r,此时word1变为rhor,由于此时word1 的第一个字符等于word2的第一个字符,可以放心的忽略掉,因此我们得到了子问题EditDistance("hor","o"),由于执行了一次新增操作,因此:

EditDistance("hor","ro")=EditDistance("hor","o")+1

2,将word1的第一个字符删掉(Delete),此时word1变为“or”,我们得到了一个新的子问题EditDistance("or","ro"),由于执行了一次删除操作,因此:

EditDistance("hor","ro")=EditDistance("or","ro")+1

3,将word1的第一个字符替换(Replace )为r,此时word1变为了“ror”,由于word1的第一个字符等于word2的第一个字符,因此可以放心的忽略掉,我们得到了一个新的子问题EditDistance("or","o"),由于执行了一次删除操作,因此:

EditDistance("hor","ro")=EditDistance("or","o")+1

根据题目要求,我们需要得到最小的编辑距离,因此:

EditDistance("hor","ro")=min(EditDistance("hor","o"),
EditDistance("or","ro"),
EditDistance("or","o"))+1

即:

4c20a8ce-d75a-11ed-bfe3-dac502259ad0.png

可以看到,如果word1与word2的第一个字符如果不相等的话那么我们会得到三个子问题,取这三个子问题的最小值然后加1就是原始问题的解。

现在我们找到了子问题与原始问题之间的依赖关系。

实际上,根据上述讨论我们还可以进一步扩展从而得到完整的状态空间树。

4c3f8104-d75a-11ed-bfe3-dac502259ad0.png

从这棵树中可以看到最小的编辑距离是2。

现在你应该清楚的知道该怎样我们是怎样一步步将问题不断的分解为更小的子问题,然后利用子问题的解来得到原始问题的解了。

自顶向下递归代码

上图中每个方框都是一个子问题,决定一个子问题的因素在于word1与word2当前处理到了哪个位置,假设对word1处理到了第i个位置,对word2处理到了第j个位置,因此我们可以对问题进行定义:

intEditDistance(inti,intj);

该函数表示从i到word1的末尾形成的字符串与从j从word2的末尾形成的字符串的编辑距离。

因此如果调用该函数时我们应该这样使用:

EditDistance(0,0);

有了该定义与上述分析,你可以轻而易举的写出这样的递归代码:

stringword1;
stringword2;

intEditDistance(inti,intj){
if(i==word1.length()&&j==word2.length())return0;
if(i==word1.length())returnword2.length()-j;
if(j==word2.length())returnword1.length()-i;

if(word1[i]==word2[j])returnEditDistance(i+1,j+1);
else{
returnmin(EditDistance(i+1,j+1),min(
EditDistance(i,j+1),
EditDistance(i+1,j)))+1;
}
}

我们将word1与word2声明为全局变量,这样你可以清楚的看到决定EditDistance函数值的因素只有这两个参数i和j,i的取值为[0, word1.length()],j的取值为[0, word2.length()],也就是说子问题的个数只有(word1.length() + 1) * (word2.length() + 1) 个,上述递归代码存在大量重复计算问题,因此可以通过增加cache进行优化,这个改动就留给大家啦。

接下来我们着手将自顶向下的递归代码改为自底向上的动态规划代码。

自底向上动态规划代码

由于子问题的个数只有(word1.length() + 1) * (word2.length() + 1) 个,因此可以定义一个相同大小的二维数组dp:

vector>dp(word1.length()+1,vector(word2.length()+1,0));

接下来我们要求解最小子问题,最小子问题就是上述递归代码的递归出口:

if(i==word1.length()&&j==word2.length())return0;

该最小子问题的解包含在了dp数组的初始化中。

接下来的子问题是另外两个递归出口:

if(i==word1.length())returnword2.length()-j;
if(j==word2.length())returnword1.length()-i;

我们可以简单的构造出两种情况下的所有i和j来初始化数组dp,即:

for(intj=word2.length()-1;j>=0;j--)
dp[word1.length()][j]=word2.length()-j;
for(inti=word1.length()-1;i>=0;i--)
dp[i][word2.length()]=word1.length()-i;

最后我们利用两个for循环来构造出所有的i和j,从而将递归函数的最后一部分:

if(word1[i]==word2[j])returnEditDistance(i+1,j+1);
else{
returnmin(EditDistance(i+1,j+1),min(
EditDistance(i,j+1),
EditDistance(i+1,j)))+1;
}

放置在for循环中,并将对递归函数的调用替换为对数组dp的读写:

for(inti=word1.length()-1;i>=0;i--){
for(intj=word2.length()-1;j>=0;j--){
if(word1[i]==word2[j])
dp[i][j]=dp[i+1][j+1];
else
dp[i][j]=min(dp[i+1][j+1],min(dp[i][j+1],dp[i+1][j]))+1;
}
}

最终,完整的动态规划代码为:

intminDistance(stringword1,stringword2){
vector>dp(word1.length()+1,vector(word2.length()+1,0));
for(intj=word2.length()-1;j>=0;j--)
dp[word1.length()][j]=word2.length()-j;
for(inti=word1.length()-1;i>=0;i--)
dp[i][word2.length()]=word1.length()-i;
for(inti=word1.length()-1;i>=0;i--){
for(intj=word2.length()-1;j>=0;j--){
if(word1[i]==word2[j])
dp[i][j]=dp[i+1][j+1];
else
dp[i][j]=min(dp[i+1][j+1],min(dp[i][j+1],dp[i+1][j]))+1;
}
}

returndp[0][0];
}





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 状态机
    +关注

    关注

    2

    文章

    502

    浏览量

    29427

原文标题:彻底理解动态规划:编辑距离

文章出处:【微信号:TheAlgorithm,微信公众号:算法与数据结构】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    [VirtualLab] VirtualLab Fusion中的参数耦合

    Extension”和“Distance”。 配置参数的耦合 选择参数后,必须设置控制耦合的代码段。单击“Edit”(编辑)打开源代码编辑器。 **配置参数的耦合 ** **配置
    发表于 05-27 08:15

    PI‑36 双 MIC 降噪拾音模块|远距离高清拾音・强降噪・易集成

    PI‑36 双麦降噪拾音模块,是专为远距离、高保真、强抗噪打造的数字 DSP 音频处理模块。它以双核算力、专业阵列算法、自适应工作模式,彻底解决噪音干扰、拾音距离近、音量忽大忽小、集成调试复杂等行业
    的头像 发表于 04-27 11:14 250次阅读
    PI‑36 双 MIC 降噪拾音模块|远<b class='flag-5'>距离</b>高清拾音・强降噪・易集成

    LORA无线数传电台传输距离:5KM双向透传,RS485转LORA

    。而LORA无线数传电台,尤其是支持5KM双向透传、RS485转LORA功能的产品,正成为解决这些痛点的“刚需神器”。 一、核心价值 先澄清一个常见认知:很多人误以为“无线传输距离越远,稳定性越差”,但LORA技术的出现,彻底打破了这个
    的头像 发表于 02-28 16:36 861次阅读

    法兰距离:相机镜头系统的关键参数

    在视觉领域,法兰距是一个重要的概念。它通常指的是相机镜头安装法兰的参考平面到成像传感器的距离,这一参数在机器视觉领域充当重要角色,法兰距离的精准性作为一个核心参数,它的精准性直接影响到成像质量
    的头像 发表于 01-28 17:29 1555次阅读
    法兰<b class='flag-5'>距离</b>:相机镜头系统的关键参数

    钉钉正式开源HarmonyOS图片编辑组件

    近日,由钉钉团队自主研发的“HarmonyOS图片编辑组件”正式上线OpenHarmony三方库中心仓并开源。作为一款填补鸿蒙社区图像处理领域空白的重量级组件,该方案基于HarmonyOS
    的头像 发表于 01-05 09:58 770次阅读

    永磁体的磁感应强度与距离的关系

    ):常指到磁极表面的垂直距离(轴向距离),或到磁体几何中心的距离;②对无明确磁极的永磁组件(如电机内置磁钢):指到磁体有效磁场作用区域的最短直线距离。 在永磁体中,
    的头像 发表于 12-25 08:39 929次阅读
    永磁体的磁感应强度与<b class='flag-5'>距离</b>的关系

    图文详情编辑接口的设计与实现

    ​  在内容管理系统(如电商平台、博客或新闻应用)中,图文详情编辑是一个核心功能。它允许用户动态创建、更新和删除图文内容(如产品描述、文章正文)。一个高效、易用的接口能显著提升用户体验和开发效率
    的头像 发表于 10-23 16:37 556次阅读
    图文详情<b class='flag-5'>编辑</b>接口的设计与实现

    图文详情编辑接口

    逐步讲解接口的设计、实现和使用,帮助您理解如何构建一个可靠的技术方案。 1. 接口设计原则 设计图文详情编辑接口时,需考虑以下关键点: 数据模型 :图文内容通常包含文本字段(如标题、正文)和图片字段(如图片URL或二进制数据)。例
    的头像 发表于 10-23 16:24 498次阅读
    图文详情<b class='flag-5'>编辑</b>接口

    跨越空间界限:远距离无线充电如何重塑机器人工作半径

    无需精准对准,无需停靠打断,磁共振技术让机器人在运动中获取能量,彻底解放工作半径。 在青岛鲁渝能源的实验室,一台AGV正在演示一场静默的变革:当电量不足时,它无需精确对准,只需经过一个充电区域,便能
    的头像 发表于 10-17 16:35 980次阅读

    Altium Designer集成库如何进行离散编辑

    集成库是一个原理图库和PCB封装库对应好封装的一个集合库,集成库的方便就是可以直接调用,但是往往我们需要对封装库添加或者修改,集成库是已经封装好了不能进行编辑,如果需要编辑我们需要先离散。
    的头像 发表于 10-16 11:06 1362次阅读
    Altium Designer集成库如何进行离散<b class='flag-5'>编辑</b>

    Melexis“Distance-to-Spot”视觉工作室简化远红外温度传感器的选型流程

    Melexis(迈来芯)宣布,受性能和应用因素(包括目标物体的大小和距离)影响,选择合适的非接触式远红外(FIR)传感器颇具挑战性。人工评估不仅复杂耗时,还可能浪费开发资源。为解决这一问题,迈来芯推出了一款在线工具“Distance-to-Spot”,为其MLX90614
    的头像 发表于 09-22 17:45 935次阅读

    【Milk-V Duo S 开发板免费体验】DuoS 超声波测距 OLED 显示

    GND GND SDA B11 SCL B12 软件说明 超声波测距 •TRIG 脉冲触发:发送 10μs 高电平 •ECHO 高电平持续时间 ∝ 距离距离计算公式:距离 = (高电平时间 * 声速
    发表于 08-22 03:55

    HarmonyOSAI编程编辑区代码续写

    利用AI大模型分析并理解开发者在代码编辑区的上下文信息或自然语言描述信息,智能生成符合上下文的ArkTS或C++代码片段。 使用约束 建议在编辑区内已有较丰富上下文,能够使模型对编程场景有一定
    发表于 08-21 15:43

    HarmonyOSAI编程编辑区代码生成

    CodeGenie提供Inline Edit能力,支持在编辑窗口中通过自然语言进行问答,基于上下文智能生成代码片段,提升代码可读性。 当前有以下两种方式唤醒Inline Edit对话框: 在代码
    发表于 08-20 15:24

    距离传输新突破:山泽HDMI线确保信号稳定无损

    、色彩失真甚至无法正常显示的问题。然而,随着技术的进步,山泽HDMI线带来了全新的解决方案,即使在长距离传输下也能确保信号稳定无损,彻底解决了这一难题。 一、高带宽支持,满足超高清需求 要实现长距离下的高清稳定传输,首
    的头像 发表于 08-10 15:06 4488次阅读