编辑距离详解:算法原理与递归实现

给定两个字符串 s1 和 s2,以及我们可以对 s1 执行的一系列操作。我们的任务找到将 s1 转换为 s2 所需的最少编辑次数(操作数)

  • 插入:在 s1 的任意索引之前或之后插入任意字符。
  • 删除:删除 s1 中的一个字符。
  • 替换:用其他字符替换 s1 中任意索引处的字符。

注意: 上述所有操作的代价都是相等的。
示例:

> 输入: s1 = "geek", s2 = "gesek"

> 输出: 1

> 解释: 我们可以通过在 s1 中两个连续的 ‘e‘ 之间插入一个 ‘s‘ 来将 s1 转换为 s2。

>

> 输入: s1 = "gfg", s2 = "gfg"

> 输出: 0

> 解释: 两个字符串完全相同。

>

> 输入: s1 = "abcd", s2 = "bcfe"

> 输出: 3

> 解释: 我们可以通过删除 ‘a‘,将 ‘d‘ 替换为 ‘f‘,并在末尾插入 ‘e‘ 来将 s1 转换为 s2。

在线练习此题!
编辑距离图解:

> 假设我们有 s1="GEEXSFRGEEKKS"s2="GEEKSFORGEEKS"

> 现在要将 s1 转换为 s2,我们需要至少 3 步操作:

> 操作 1: 将 ‘X‘ 替换为 ‘K‘

> 操作 2: 在 ‘F‘ 和 ‘R‘ 之间插入 ‘O‘

> 操作 3: 删除倒数第二个字符,即 ‘K‘

>

> 请参考下图以更好地理解。

> !Edit-Distance-Illustration-copy.webp)

[朴素方法] 使用递归 – 时间复杂度 O(3^(m+n)),空间复杂度 O(m*n)

> 这个思路是从两个字符串的左侧右侧开始,逐一处理所有字符。

> 让我们从字符串的右侧开始处理,对于正在遍历的每一对字符,存在两种可能性:要么它们匹配,要么它们不匹配。如果两个字符串的最后一个字符匹配,我们只需简单地递归计算字符串剩余部分的答案。当最后一个字符不匹配时,我们执行所有三种操作来使最后的字符匹配,即插入、替换和删除。然后递归计算字符串剩余部分的结果。完成这些操作后,我们将选择最小的答案并将其加 1。

>

> 下面是针对此问题的递归树,考虑了最后字符始终不匹配的情况。

> !Recursion Tree.png)

> 当字符串的最后一个字符匹配时。发起递归调用 editDistance(m-1, n-1) 来计算字符串剩余部分的答案。

>

> 当字符串的最后一个字符不匹配时。发起三个递归调用,如下所示:

>

> – 在 s1 的末尾插入 s2[n-1] : editDistance(m, n-1)

> – 将 s1[m-1] 替换为 s2[n-1] : editDistance(m-1, n-1)

> – 删除 s1[m-1] : editDistance(m-1, n)

编辑距离的递推关系:

> – 情况 1:当两个字符串的最后一个字符相同时。editDistance(s1, s2, m, n) = editDistance(s1, s2, m-1, n-1)

> – 情况 2:当最后一个字符不同时

> – editDistance(s1, s2, m, n) = 1 + Min{ editDistance(s1, s2 ,m,n-1), editDistance(s1, s2 ,m-1, n), editDistance(s1, s2 , m-1, n-1)}

编辑距离的基本情况:

> – 情况 1:当 s1 变为空字符串时,即 m=0

> – 返回 n,因为将空字符串转换为长度为 ns2 需要 n 次插入操作。

> – 情况 2:当 s2 变为空字符串时,即 n=0

> – 返回 m,因为将长度为 m 的 s1 转换为空字符串需要 m 次删除操作。

C++

INLINECODE6c5341a0`INLINECODEfac91a29

[动态规划方法] 使用 DP Memoization (自顶向下) – 时间复杂度 O(mn),空间复杂度 O(mn)

> 在上述递归方法中,存在许多重叠的子问题。请参见上面的递归树图,其中存在许多重复的子树。我们使用 Memoization 技术来避免重新计算。我们在递归函数开始时检查结果是否已经计算出来,如果是,则直接返回存储的结果。

#### 辅助空间:O(m*n) + O(m+n)

这里,O(m*n) 用于存储 dp 数组/表,O(m+n) 是递归栈空间。

C++

INLINECODEaa0f98c3`INLINECODEd15eaf7a

[动态规划方法] 使用 Tabulation (自底向上) – 时间复杂度 O(mn),空间复杂度 O(mn)

> 我们可以创建一个二维数组 dp[m+1][n+1] 来存储子问题的解。在自底向上的方法中,我们首先解决较小的子问题,然后从中解决较大的子问题。

#### 辅助空间:O(m*n)

C++

INLINECODE4640901b`INLINECODEb00144d6

空间优化方法 – 时间复杂度 O(m*n),空间复杂度 O(n)

> 在上面的方法中,我们只使用了前一行(INLINECODE3bd9649f)和当前行(INLINECODE0218d386)的数据来计算结果。因此,我们不需要整个二维矩阵,只需要两个一维数组来存储前一行和当前行的结果。

C++

INLINECODEf9a7a272`INLINECODEb5d5025a

进一步的空间优化(仅使用一维数组)- 时间复杂度 O(m*n),空间复杂度 O(n)

> 我们还可以进一步优化空间,仅使用一个一维数组 INLINECODE7f5e77c1 和一个变量来存储 INLINECODEc9db59d6(对角线值)。

C++

INLINECODEd279b5ca`INLINECODE14078e12“

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/25517.html
点赞
0.00 平均评分 (0% 分数) - 0