【动态规划】求解编辑距离问题

这篇具有很好参考价值的文章主要介绍了【动态规划】求解编辑距离问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

问题描述

编辑距离问题是求解将⼀个字符串转换为另⼀个字符串所需的插⼊、删除、替换的最小次数。 C O M M O M → s u b C O M M U M → s u b C O M M U N → i n s C O M M U N E \mathbb{COMMOM} \overset{sub}{\rightarrow} \mathbb{COMMUM} \overset{sub}{\rightarrow}\mathbb{COMMUN} \overset{ins}{\rightarrow} \mathbb{COMMUNE} COMMOMsubCOMMUMsubCOMMUNinsCOMMUNE上述将单词 COMMOM 变为 COMMUNE 共需要经过至少3次操作。

对编辑距离进行可视化,可以得到序列比对

C O M M O M -
C O M M U N E
  • 第一行的空格表示插入
  • 第二行的空格表示删除
  • 具有不同字符的列表示替换

编辑距离 = 序列比对中具有不同字符的列数

最小编辑距离 = 最优序列比对中具有不同字符的列数

编辑距离问题也可以这么表述:
对于给定字符串 A [ 1... m ] A[1...m] A[1...m] B [ 1... n ] B[1...n] B[1...n] 求解他们的最小编辑距离 D ( m , n ) D(m,n) D(m,n)


递推关系

假设对 ∀ i < m , ∀ j < n \forall i<m,\forall j<n i<m,j<n,可以计算 A [ 1... i ] A[1...i] A[1...i] B [ 1... j ] B[1...j] B[1...j]的最小编辑距离 D ( i , j ) D(i,j) D(i,j)

C O M M O M -
C O M M U N E

考虑 A [ 1... m ] A[1...m] A[1...m] B [ 1... n ] B[1...n] B[1...n] 的最优比对,可以发现如下规律:

  1. 最后⼀列不可能是两个空格
  2. 某个串为空串时,最小编辑距离是另⼀个串的长度
  3. A [ m ] A[m] A[m] B [ n ] B[n] B[n] 都存在: D ( m , n ) = D ( m − 1 , n − 1 ) + ( A [ m ] = B [ n ] ? 0 : 1 ) D(m,n) =D(m − 1,n − 1) + (A[m] = B[n]?0 : 1) D(m,n)=D(m1,n1)+(A[m]=B[n]?0:1)
  4. A [ m ] A[m] A[m] B [ n ] B[n] B[n] 有一方为空,删除不为空的那一个: D ( m , n ) = { D ( m − 1 , n ) + 1 A [ m ] a n d − D ( m , n − 1 ) + 1 B [ n ] a n d − D(m,n) = \begin{cases} D(m − 1,n) + 1 & A[m]\quad and \quad- \\ D(m, n − 1) + 1 & B[n]\quad and \quad- \\ \end{cases} D(m,n)={D(m1,n)+1D(m,n1)+1A[m]andB[n]and
  5. 综上,只需要沿着三条路径递归得到最小的那条 D ( m , n ) = { i i f j = 0 j i f i = 0 min ⁡ { D ( m − 1 , n ) + 1 D ( m , n − 1 ) + 1 D ( m − 1 , n − 1 ) + ( A [ m ] = B [ n ] ? 0 : 1 ) o t h e r w i s e D(m,n) = \begin{cases} i &if\quad j=0\\ j &if\quad i=0 \\ \min \begin{cases} D(m − 1,n) + 1 \\ D(m, n − 1) + 1 \\ D(m − 1,n − 1) + (A[m] = B[n]?0 : 1) \end{cases} &otherwise \end{cases} D(m,n)= ijmin D(m1,n)+1D(m,n1)+1D(m1,n1)+(A[m]=B[n]?0:1)ifj=0ifi=0otherwise
  6. 时间复杂度: O ( m n ) O(mn) O(mn) ; 空间复杂度: O ( m n ) O(mn) O(mn)

运行实例

字符串编辑动态规划求解的,算法学习,动态规划,算法,editDistance
对于每个 D [ i , j ] D[i,j] D[i,j], 都可以通过 D [ i − 1 , j − 1 ] D[i-1,j-1] D[i1,j1]; D [ i − 1 , j ] D[i-1,j] D[i1,j]; D [ i , j − 1 ] D[i,j-1] D[i,j1]这三个点得到而这三个点又分别对应 替换;删除;插入三种操作。

通过上述递推关系,我们可以自上而下,自左向右构造记录表。在填完记录表后右下角的那个值即为最小编辑距离。接着就是使用回溯的方式,构造满足最小编辑距离的最优比对(如下图右侧所示)
字符串编辑动态规划求解的,算法学习,动态规划,算法,editDistance

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>

using namespace std;

// 计算最小编辑距离,并返回最小编辑距离的值,计算编辑距离表dp
int minEditDistance(const string& word1, const string& word2, vector<vector<int>>& dp) {
    int m = word1.length();
    int n = word2.length();

    for (int i = 0; i <= m; ++i) {
        for (int j = 0; j <= n; ++j) {
            if (i == 0) {
                dp[i][j] = j;
            }
            else if (j == 0) {
                dp[i][j] = i;
            }
            else if (word1[i - 1] == word2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1];
            }
            else {
                dp[i][j] = 1 + min({ dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1] });
            }
        }
    }

    return dp[m][n];
}

// 通过回溯法找到所有满足最小编辑距离的操作序列。
void findAllSequences(const string& word1, const string& word2, int i, int j, const string& sequence, vector<string>& sequences, vector<vector<int>>& dp) {
    if (i == 0 && j == 0) {
        sequences.push_back(sequence);
        return;
    }

    if (i > 0 && j > 0 && word1[i - 1] == word2[j - 1]) {
        findAllSequences(word1, word2, i - 1, j - 1, "No operation: " + string(1, word1[i - 1]) + " -> " + string(1, word2[j - 1]) + "\n" + sequence, sequences, dp);
    }

    if (i > 0 && j > 0 && dp[i][j] == dp[i - 1][j - 1] + 1) {
        findAllSequences(word1, word2, i - 1, j - 1, "Replace: " + string(1, word1[i - 1]) + " -> " + string(1, word2[j - 1]) + "\n" + sequence, sequences, dp);
    }

    if (i > 0 && dp[i][j] == dp[i - 1][j] + 1) {
        findAllSequences(word1, word2, i - 1, j, "Delete: " + string(1, word1[i - 1]) + " \n" + sequence, sequences, dp);
    }

    if (j > 0 && dp[i][j] == dp[i][j - 1] + 1) {
        findAllSequences(word1, word2, i, j - 1, "Insert: " + string(1, word2[j - 1]) + " \n" + sequence, sequences, dp);
    }
}

int main() {
    string word1 = "ALTRUISTIC";
    string word2 = "ALGORITHM";

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

    int minDistance = minEditDistance(word1, word2, dp);

    cout << "Minimum Edit Distance between " << word1 << " and " << word2 << " is: " << minDistance << endl;

    vector<string> sequences;
    findAllSequences(word1, word2, word1.length(), word2.length(), "", sequences, dp);

    cout << "Operations to convert " << word1 << " to " << word2 << " are: " << endl;
    for (const string& seq : sequences) {
        cout << seq << "----------"<< endl;
    }

    return 0;
}

运行结果:

字符串编辑动态规划求解的,算法学习,动态规划,算法,editDistance


时空复杂度优化

现在我们已经可以计算最小编辑距离,同时构造出最优比对。他们的时空复杂度总结如下:

计算最小编辑距离 构造最优比对
时间 O ( m n ) O(mn) O(mn) O ( m + n ) O(m+n) O(m+n)
空间 O ( m n ) O(mn) O(mn) O ( m n ) O(mn) O(mn)

从实际情况来看, O ( m n ) O(mn) O(mn) 的空间比 O ( m n ) O(mn) O(mn) 的时间更难满足,比如当 m = n = 1 0 5 m = n = 10^5 m=n=105

  • 时间上:执行 1 0 10 10^{10} 1010次指令大约需要10秒(假设CPU每秒执行 1 0 9 10^9 109条指令)
  • 空间上:需要 1 0 10 10^{10} 1010bits,大约 40 GB

那么能否使用 O ( m + n ) O(m+n) O(m+n) 的空间来构造最优比对呢?

答:可以使用 Hirschberg 算法。


Hirschberg 算法

Hirschberg 算法是一种高效的线性空间动态规划算法。它通过使用分治策略来降低空间复杂度,从而在线性空间内计算最优比对。

该算法的思想基于以下洞察力:

  • 在动态规划算法中,通常使用二维矩阵来存储中间状态,这导致了 O ( m n ) O(mn) O(mn) 的空间复杂度。
  • 但实际上,可以通过观察计算过程中的对称性,将动态规划的空间复杂度降低到 O ( m + n ) O(m+n) O(m+n)

字符串编辑动态规划求解的,算法学习,动态规划,算法,editDistance
在计算动态规划的过程中,我们观察到 D ( i , j ) D(i,j) D(i,j) 的计算仅依赖于 D ( i − 1 , j ) D(i-1,j) D(i1,j) D ( i , j − 1 ) D(i,j-1) D(i,j1) D ( i − 1 , j − 1 ) D(i-1,j-1) D(i1,j1)。基于此,我们可以利用两个长度为 n 的一维数组来存储中间状态,每次只需要保留上一行和当前行的信息。文章来源地址https://www.toymoban.com/news/detail-781563.html

到了这里,关于【动态规划】求解编辑距离问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【LeetCode动态规划#10】完全背包问题实战,其三(单词拆分,涉及集合处理字符串)

    力扣题目链接(opens new window) 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。 说明: 拆分时可以重复使用字典中的单词。 你可以假设字典中没有重复的单词。 示例 1: 输入: s = \\\"leetcode\\\", wordDict = [\\\"lee

    2023年04月20日
    浏览(61)
  • 【dp】不同的子序列 & 两个字符串的删除操作 & 编辑距离

    dp[i][j]:以j-1为结尾的t出现在以i-1为结尾的s子序列的个数 需要开辟m+1行,n+1列的二维数组 为啥状态方程是: s[i] == t[j] 时 dp[i][j] = dp[i-1][j-1] + dp[i-1][j] s[i] != t[j] 时 dp[i][j] = dp[i-1][j] 先看s[i] == t[j] 时,以s = “rara” t = “ra” 为例,当i = 3, j = 1时,s[i] == t[j] 此时分为2种情况:

    2023年04月15日
    浏览(45)
  • 代码随想录第五十六天——两个字符串的删除操作,编辑距离

    题目链接:两个字符串的删除操作 两个字符串可以相互删除 版本一: 确定dp数组及下标的含义 dp[i][j] :以i-1为结尾的字符串word1,和以j-1为结尾的字符串word2,想要达到相等,所需要删除元素的最少次数 确定递推公式 (1)当word1[i - 1] 与 word2[j - 1]相同: (2)当word1[i - 1] 与

    2024年02月02日
    浏览(40)
  • 代码随想录打卡第56天|583. 两个字符串的删除操作;72. 编辑距离

    583. 两个字符串的删除操作 关键点1:dp数组的含义 dp[i][j],使得以i-1为结尾word1 和 以j-1为结尾的word2 相同所需的最小步数; 关键点2:递归公式的推导 if(nums1[i-1] == nums2[j-1]),则i和j同时移动,所以为i-1,j-1;dp[i][j] = dp[i-1][j-1];由于不需要进行删除操作,所以不需要加1 如果不相

    2023年04月19日
    浏览(51)
  • 【动态规划】【字符串】扰乱字符串

    视频算法专题 动态规划汇总 字符串 使用下面描述的算法可以扰乱字符串 s 得到字符串 t : 如果字符串的长度为 1 ,算法停止 如果字符串的长度 1 ,执行下述步骤: 在一个随机下标处将字符串分割成两个非空的子字符串。即,如果已知字符串 s ,则可以将其分成两个子字符

    2024年02月03日
    浏览(60)
  • 【学会动态规划】环绕字符串中唯一的子字符串(25)

    目录 动态规划怎么学? 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后: 学习一个算法没有捷径,更何况是学习动态规划, 跟我一起刷动态规划算法题,一起学会动态规划! 题目链接:467. 环绕字符串中唯一的子字

    2024年02月10日
    浏览(38)
  • 动态规划--通配字符串匹配

    1. 题目来源 链接:通配符匹配 来源:LeetCode 2. 题目说明 给定一个字符串 (s) 和一个字符模式 § ,实现一个支持 ‘?’ 和 ‘*’ 的通配符匹配。 ‘?’ 可以匹配任何单个字符。 ‘*’ 可以匹配任意字符串(包括空字符串)。 两个字符串完全匹配才算匹配成功。 说明: s 可能为

    2024年02月14日
    浏览(52)
  • 【面试经典150 | 动态规划】交错字符串

    本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更…… 专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删: Tag:介绍本题牵涉到的知识点、数据结构; 题目来源:

    2024年04月15日
    浏览(68)
  • 【动态规划----“最小编辑距离”问题(C++解决)】

    给定两个字符串A和B,以及下列三种字符运算: (1)删除一个字符(2)插入一个字符(3)将一个字符改写为另一个字符 设计算法求将A通过以上三种操作转换为B的最小次数 举例: “xy” = “xz”,只需要把 y 替换成 z,因此,最小编辑距离为 1。 “xyz” = “xy”,只需要删除

    2024年04月25日
    浏览(86)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包