首页 > 其他分享 >编辑最短距离

编辑最短距离

时间:2024-11-18 11:17:43浏览次数:3  
标签:字符 删除 编辑 word1 短距离 word2 替换 dp

*************

C++

题目来源:72. 编辑距离 - 力扣(LeetCode)

*************

看一下题目

想到了小时候暑假的某天下午,阳光热烈,老师在讲台上讲课,粉笔灰在透过窗台的阳光中慢慢的降落,我顾不上那一刻的达尔文效应,我在冥思苦想汉诺塔,虽然跟这个没啥关系,但是就是突然想起来这个场景。为什么人在回忆自己的事情的时候是第三视角,而不是第一视角呢?

首先,矩阵的起手式已经非常的成熟了, 先数出来两个单词的长度m 和 n,这个用于构建矩阵,然后把矩阵初始化为0,之后填充第一行第一列,这步很快,无他,唯手熟尔。

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));
        
        // initialise the first column
        for (int i = 0; i <= m; ++i) {
            dp[i][0] = i;
        }

        // initialise the first row
        for (int j = 0; j <= n; ++j) {
            dp[0][j] = j;
        }
        
    }
};

其次,举例美学:

word1 = else; word2 = where

初始化这个过程比较简单,就是

第一列 dp[i][0] = i,表示将 word1 的前 i 个字符转换为空字符串需要 i 次删除操作。

第一行 dp[0][j] = i,表示将 word2 的前 j 个字符转换为空字符串需要 j 次删除操作。

where
012345
e1
l2
s3
e4

完美的矩阵,接下来就是填充剩下的矩阵了,涉及到元素的替换只有三种方式,删除,插入和替换。假设我是计算机,我首先会遍历一下单词的所有元素,每个字母只有三种状态,删除、插入和替换。分别对应下面的公式:

  • dp[i-1][j]:删除 word1[i-1]

  • dp[i][j-1]:插入 word2[j-1]

  • dp[i-1][j-1]:替换 word1[i-1] 为 word2[j-1]

填充 dp[1][1]
  • word1[0] = 'e'word2[0] = 'w',字符不同。

  • 计算 dp[1][1]

  • 删除操作dp[0][1] = 1,删除字母 w

  • 插入操作dp[1][0] = 1,插入字母 w

  • 替换操作dp[0][0] = 0,替换字母 w

这里选择删除或者插入:

  • 删除操作:删除 word1 的第一个字符 e,使其与 word2 的第一个字符 w 匹配。此时,编辑距离为 dp[0][1] + 1 = 1 + 1 = 2

  • 插入操作:在 word1 的第一个字符 e 之前插入 word2 的第一个字符 w,使其与 word2 的第一个字符 w 匹配。此时,编辑距离为 dp[1][0] + 1 = 1 + 1 = 2

  • 替换操作:将 word1 的第一个字符 e 替换为 word2 的第一个字符 w,使其与 word2 的第一个字符 w 匹配。此时,编辑距离为 dp[0][0] + 1 = 0 + 1 = 1

最小值是1,所以填充1。至于为什么要 + 1, 我也是想了很久才想起来,本来周五晚上写的,没加注释的话,当时想的是只有我和佛祖知道,等到我再看代码的时候,不禁感慨,完了,只有佛祖知道了。

在每种情况下,加1是为了计算从 word1 的前 i-1 个字符到 word2 的前 j-1 个字符所需的操作次数,再加上当前的编辑操作。

例如,如果我正在计算 dp[1][1] 并且我选择替换操作,我从 dp[0][0](即0)开始,然后加1来反映替换操作,得到 dp[1][1] = 1。这个1表示将 word1 的第一个字符 'e' 替换为 word2 的第一个字符 'w',这是将 'e' 转换为 'w' 所需的唯一操作。

更新矩阵:

where
012345
e11
l2
s3
e4

填充 dp[1][2]
  • word1[0] = 'e'word2[1] = 'h',字符不同。

计算 dp[1][2]

  • 删除操作dp[0][2] = 2,删除字母 h

  • 插入操作dp[1][1] = 1,插入字母 h

  • 替换操作dp[0][1] = 1,替换字母 h

这里选择删除或者插入:

  • 删除操作:删除 word1 的第一个字符 e,使其与 word2 的第二个字符 h 匹配。此时,编辑距离为 dp[0][2] + 1 = 2 + 1 = 3

  • 插入操作:在 word1 的第一个字符 e 之前插入 word2 的第二个字符 h,使其与 word2 的第二个字符 h 匹配。此时,编辑距离为 dp[1][1] + 1 = 1 + 1 = 2

  • 替换操作:将 word1 的第一个字符 e 替换为 word2 的第二个字符 h,使其与 word2 的第二个字符 h 匹配。此时,编辑距离为 dp[0][1] + 1 = 1 + 1 = 2

最小值为 1,加一后为 2

更新矩阵:

where
012345
e112
l2
s3
e4

填充 dp[1][3]
  • word1[0] = 'e'word2[2] = 'e',字符相同。

计算 dp[1][3]

  • 删除操作dp[0][3] = 3,删除字母 e

  • 插入操作dp[1][2] = 2,插入字母 e

  • 替换操作dp[0][2] = 2,替换字母 e

这里选择删除或者插入:

  • 删除操作:删除 word1 的第一个字符 e,使其与 word2 的第三个字符 e 匹配。此时,编辑距离为 dp[0][3] + 1 = 3 + 1 = 4

  • 插入操作:在 word1 的第一个字符 e 之前插入 word2 的第三个字符 e,使其与 word2 的第三个字符 e 匹配。此时,编辑距离为 dp[1][2] + 1 = 2 + 1 = 3

  • 替换操作:将 word1 的第一个字符 e 替换为 word2 的第三个字符 e,使其与 word2 的第三个字符 e 匹配。此时,编辑距离为 dp[0][2] + 1 = 2 + 1 = 3

最小值为 2,加一后为 3

更新矩阵:

where
012345
e1123
l2
s3
e4
填充 dp[1][4]
  • word1[0] = 'e'word2[3] = 'r',字符不同。

计算 dp[1][4]

  • 删除操作dp[0][4] = 4,删除字母 r

  • 插入操作dp[1][3] = 2,插入字母 r

  • 替换操作dp[0][3] = 3,替换字母 r

这里选择删除或者插入:

  • 删除操作:删除 word1 的第一个字符 e,使其与 word2 的第四个字符 r 匹配。此时,编辑距离为 dp[0][4] + 1 = 4 + 1 = 5

  • 插入操作:在 word1 的第一个字符 e 之前插入 word2 的第四个字符 r,使其与 word2 的第四个字符 r 匹配。此时,编辑距离为 dp[1][3] + 1 = 2 + 1 = 3

  • 替换操作:将 word1 的第一个字符 e 替换为 word2 的第四个字符 r,使其与 word2 的第四个字符 r 匹配。此时,编辑距离为 dp[0][3] + 1 = 3 + 1 = 4

  • 更新矩阵

where
012345
e11233
l2
s3
e4
填充 dp[1][5]
  • word1[0] = 'e'word2[4] = 'e',字符相同。

计算 dp[1][5]

  • 删除操作dp[0][5] = 5,删除字母 e

  • 插入操作dp[1][4] = 3,插入字母 e

  • 替换操作dp[0][4] = 4,替换字母 e

这里选择删除或者插入:

  • 删除操作:删除 word1 的第一个字符 e,使其与 word2 的第五个字符 e 匹配。此时,编辑距离为 dp[0][5] + 1 = 5 + 1 = 6

  • 插入操作:在 word1 的第一个字符 e 之前插入 word2 的第五个字符 e,使其与 word2 的第五个字符 e 匹配。此时,编辑距离为 dp[1][4] + 1 = 3 + 1 = 4

  • 替换操作:将 word1 的第一个字符 e 替换为 word2 的第五个字符 e,使其与 word2 的第五个字符 e 匹配。此时,编辑距离为 dp[0][4] + 1 = 4 + 1 = 5

  • 更新矩阵

where
012345
e112334
l2
s3
e4

最后,依次类推:

  1. dp[1][1]:替换 e 为 w,操作数为 1

  2. dp[1][2]:替换 e 为 h,操作数为 2

  3. dp[1][3]:字符相同,不需要操作,操作数为 2

  4. dp[1][4]:替换 e 为 r,操作数为 3

  5. dp[1][5]:字符相同,不需要操作,操作数为 4

  6. dp[2][1]:删除 l,操作数为 2

  7. dp[2][2]:替换 l 为 h,操作数为 2

  8. dp[2][3]:替换 l 为 e,操作数为 3

  9. dp[2][4]:替换 l 为 r,操作数为 3

  10. dp[2][5]:替换 l 为 e,操作数为 4

  11. dp[3][1]:删除 s,操作数为 3

  12. dp[3][2]:替换 s 为 h,操作数为 3

  13. dp[3][3]:替换 s 为 e,操作数为 3

  14. dp[3][4]:替换 s 为 r,操作数为 4

  15. dp[3][5]:替换 s 为 e,操作数为 4

  16. dp[4][1]:删除 e,操作数为 4

  17. dp[4][2]:替换 e 为 h,操作数为 4

  18. dp[4][3]:字符相同,不需要操作,操作数为 3

  19. dp[4][4]:替换 e 为 r,操作数为 4

  20. dp[4][5]:字符相同,不需要操作,操作数为 4

最终,dp[4][5] 的结果为 4,表示将 word1 = "else" 转换为 word2 = "where" 所需的最小编辑操作数为 4

OK,原理知道了,代码也就好写了:

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));
        
        // initialise the first column
        for (int i = 0; i <= m; ++i) {
            dp[i][0] = i;
        }

        // initialise the first row
        for (int j = 0; j <= n; ++j) {
            dp[0][j] = j;
        }

        // fill the dp
        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]; // need no cosplay cuz they are same
                } else {
                    dp[i][j] = min({dp[i - 1][j],    // delete
                                    dp[i][j - 1],    // insert
                                    dp[i - 1][j - 1]}) + 1; // replace
                }
            }
        }
        
        return dp[m][n];
    }
};

天冷了,注意加衣服。

标签:字符,删除,编辑,word1,短距离,word2,替换,dp
From: https://blog.csdn.net/ElseWhereR/article/details/143801406

相关文章

  • 「Java EE开发指南」如何使用Visual JSF编辑器设计JSP?(一)
    VisualJSFDesigner的目标是使创建JSF应用程序的特定于组件的工作更容易可视化,在本教程中,您将使用可视化设计器设计JSF登录页面,将学习如何:创建一个JSF项目创建一个新的JSF页面设计JSF页面该功能在MyEclipse中可用。MyEclipsev2024.1离线版下载MyEclipse技术交流群:74233......
  • 编辑器vim 命令的学习
    1.编辑器Vim1.vim是一个专注的编辑器2.是一个支持多模式的编辑器1.1见一见:vim的本质也是一条命令退出来:->Shift+:q先创建一个文件再打开这个文件进入后先按I然后就可以输入了输入完后,保存退出按Esc-->来到最后一行-->再Shift+:wq-->再回车-->退出......
  • 网站首页修改标题描述,如何在网站后台或代码编辑器中修改首页标题和描述
    修改首页标题和描述可以提升搜索引擎优化(SEO)。以下是修改首页标题和描述的步骤:登录网站后台:打开浏览器,输入网站的后台地址,例如 http://yourdomain.com/admin。输入管理员账号和密码,点击“登录”。进入SEO设置:登录后,点击顶部菜单栏中的“SEO”或“设置”。选择“SEO......
  • Vue中,$forceUpdate()的使用(针对列入多选下拉框回显无法重新编辑
    Vue中,$forceUpdate()的使用方文档中指出,$forceUpdate具有强制刷新的作用。那在vue框架中,如果data中有一个变量:age,修改他,页面会自动更新。但如果data中的变量为数组或对象,我们直接去给某个对象或数组添加属性,页面是识别不到的<template><p>{{userInfo.name}}</p><button@......
  • (长期更新)《零基础入门 ArcGIS(ArcMap) 》实验一(下)----空间数据的编辑与处理(超超超详细
    续上篇博客(长期更新)《零基础入门ArcGIS(ArcMap)》实验一(上)----空间数据的编辑与处理(超超超详细!!!)-CSDN博客继续更新        本篇博客内容为道路拓扑检查与修正,有对本实验实验目的、实验介绍有不了解的,可以看下上篇博客。        上篇博客有宝子私信我下载......
  • 11-RCE、编辑器漏洞、旁注、hydra练习
    1、RCE:分别实现ThinkPHP、Weblogic、Shiro漏洞的利用过程ThinkPHP满足条件:多语言特性开启、安装pear库、知道pearcmd.php路径、register_argc_argv=on的前提下且ThinkPHP在漏洞版本中,再实现漏洞过程。前端访问pearcmd文件,出现如下报错确定文件存在插入代码实现文件包......
  • 【Adobe Acrobat pro 2024软件下载与安装教程-PDF编辑神奇】
    1、安装包「AdobeAcrobat2024」:链接:https://pan.quark.cn/s/86f8683afe5c提取码:4uur2、安装教程(建议关闭杀毒软件和系统防护)1)       下载软件安装包,打开安装目录,双击Setup.exe安装,弹出安装对话框   2)       点击安装按钮  3)     ......
  • 重磅!发表知网论文新规定出现,多个学报编辑部已经开始实施,大家注意!(文献管理学术助手这个
    重大通知:已经录用的论文需要提供所有参考文献的原文出处具体页面(含页码)的图片(拍照或者截图)。——多个知网期刊已经开始实施,特别是学报,凡是发表的文章,必须要提供参考文献的详细出处。话先放到这,最多3年,估计就会成为期刊社的普遍要求。PART.1其实特好理解,光是核对作者的参考......
  • Apple Logic Pro 11.1 - 专业音乐制作 (音频编辑)
    AppleLogicPro11.1-专业音乐制作(音频编辑)LogicPro配备全新AI功能,引领音乐创作再上新阶请访问原文链接:https://sysin.org/blog/apple-logic-pro/查看最新版。原创作品,转载请保留出处。作者主页:sysin.orgLogicPro配备全新AI功能,引领音乐创作再上新阶伴奏乐手......
  • 每日OJ题_牛客_计算字符串的编辑距离_DP_C++_Java
    目录牛客_计算字符串的编辑距离_DP题目解析C++代码Java代码牛客_计算字符串的编辑距离_DP计算字符串的编辑距离_牛客题霸_牛客网描述:Levenshtein 距离,又称编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换......