📜  编辑距离和 LCS(最长公共子序列)(1)

📅  最后修改于: 2023-12-03 14:56:59.567000             🧑  作者: Mango

编辑距离和 LCS(最长公共子序列)

介绍

编辑距离和 LCS 都是字符串算法中常用的算法。编辑距离计算的是两个字符串之间的最短编辑距离,也就是需要多少次修改、删除或插入操作才能将一个字符串转换为另一个字符串。而 LCS 则是用于求两个字符串之间的最长公共子序列,即相同的最长子串。

在实际应用中,编辑距离通常用于拼写纠错、自然语言处理、基因序列比对等领域;LCS 主要用于比较文本、图像、音频等领域。

编辑距离

编辑距离算法有多种实现方式,其中最常用的是动态规划。具体来说,我们可以定义一个二维数组 C,其中 C[i][j] 表示将字符串 A 的前 i 个字符变换为字符串 B 的前 j 个字符所需的最小编辑距离。

我们可以根据字符串 A 和 B 最后一个字符是否相等分成以下三种情况:

  • 如果 A[i] == B[j],则 C[i][j] = C[i-1][j-1],因为此时不需要修改操作。
  • 如果 A[i] != B[j],则我们可以进行三种操作中的任意一种来将 A 的前 i 个字符变换为 B 的前 j 个字符:
    • 在 A 的前 i 个字符后面添加一个字符,然后再将 A 的第 i+1 个字符变为 B 的第 j 个字符,此时需要的操作次数为 C[i][j-1]+1。
    • 删除 A 的第 i 个字符,此时需要的操作次数为 C[i-1][j]+1。
    • 用 B 的第 j 个字符替换 A 的第 i 个字符,此时需要的操作次数为 C[i-1][j-1]+1。
  • 对于边界情况,即当 i=0 或 j=0 时,C[i][j] = max(i,j),因为此时一个空串需要插入或删除的字符数为其长度。

根据上述定义,我们可以编写如下的 Python 代码实现编辑距离算法:

def edit_distance(A, B):
    m, n = len(A), len(B)
    C = [[0] * (n + 1) for _ in range(m + 1)]
    for i in range(m + 1):
        C[i][0] = i
    for j in range(n + 1):
        C[0][j] = j
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if A[i-1] == B[j-1]:
                C[i][j] = C[i-1][j-1]
            else:
                C[i][j] = min(C[i][j-1], C[i-1][j], C[i-1][j-1]) + 1
    return C[m][n]
最长公共子序列

LCS 也可以使用动态规划来实现。我们可以定义一个二维数组 C,其中 C[i][j] 表示字符串 A 的前 i 个字符与字符串 B 的前 j 个字符的最长公共子序列的长度。

我们可以根据字符串 A 和 B 最后一个字符是否相等分成以下两种情况:

  • 如果 A[i] == B[j],则 C[i][j] = C[i-1][j-1] + 1,即 A 和 B 的最后一个字符都在公共子序列中,最长公共子序列长度加一。
  • 如果 A[i] != B[j],则 A 和 B 的最后一个字符至少有一个不在公共子序列中,这时我们需要从下面两个子问题中选择最优解:
    • 将 A 的前 i 个字符与 B 的前 j-1 个字符的最长公共子序列与 A 的前 i-1 个字符与 B 的前 j 个字符的最长公共子序列的较大值即为 C[i][j]。
    • 将 A 的前 i-1 个字符与 B 的前 j-1 个字符的最长公共子序列与 A 的第 i 个字符与 B 的第 j 个字符的匹配作为候选结果。如果匹配成功,则 LCS 长度为 C[i-1][j-1]+1。否则,LCS 长度不变。

根据上述定义,我们可以编写如下的 Python 代码实现 LCS 算法:

def lcs(A, B):
    m, n = len(A), len(B)
    C = [[0] * (n + 1) for _ in range(m + 1)]
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if A[i-1] == B[j-1]:
                C[i][j] = C[i-1][j-1] + 1
            else:
                C[i][j] = max(C[i][j-1], C[i-1][j])
    return C[m][n]
总结

在本文中,我们介绍了编辑距离和 LCS 两个字符串算法的基本思想和实现方法。虽然这两个算法有些相似之处,但它们的应用场景不同,需要根据具体的问题选择相应的算法。熟练掌握这些算法有助于提高字符串处理的效率,让我们的程序更快、更准确。