编辑距离问题(Edit Distance)

title

编辑距离问题(Edit Distance)也是一个经典的动态规划问题,也称为 Levenshtein 距离。给定两个字符串 s 和 t,计算将 s 转换为 t 的最少操作次数,每个操作可以是插入、删除或替换一个字符。

例如,将字符串 "horse" 转换为 "ros" 需要三次操作:删除 'h',将 'r' 替换为 'o',删除 'e'。

解法:

一般来说,动态规划问题都有以下三个要素:

1.状态定义:定义状态,明确状态含义。

对于编辑距离问题,我们可以定义状态 dp[i][j] 表示将 s 中前 i 个字符转换成 t 中前 j 个字符所需要的最少操作次数。

2.状态转移:根据状态定义,设计状态转移方程。

对于状态 dp[i][j],需要考虑三种情况:

  • 对于第 i 个字符和第 j 个字符相同,此时不需要进行任何操作,因此 dp[i][j] = dp[i-1][j-1]。
  • 对于第 i 个字符和第 j 个字符不同,此时需要进行插入、删除或替换操作,需要选取其中的最小值,因此 dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1。

3.初始状态:根据状态定义,确定初始状态。

对于编辑距离问题,初始状态为 dp[i][0] = i 和 dp[0][j] = j,即将一个字符串转换为空串需要的操作次数就是字符串的长度。

最终的结果是 dp[m][n],其中 m 和 n 分别为两个字符串的长度。

具体实现代码如下:

public int minDistance(String word1, String word2) {
    int m = word1.length(), n = word2.length();
    int[][] dp = new int[m+1][n+1];
    for (int i = 0; i <= m; i++) {
        dp[i][0] = i;
    }
    for (int j = 0; j <= n; j++) {
        dp[0][j] = j;
    }

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

    return dp[m][n];
}

其中,dp 数组表示将 s 中前 i 个字符转换成 t 中前 j 个字符所需要的最少操作次数。初始时,将一个字符串转换为空串需要的操作次数就是字符串的长度。

然后,对于每个位置 i 和 j,需要分情况判断:

  • 如果 word1[i-1] 和 word2[j-1] 相同,则说明不需要进行任何操作,因此 dp[i][j] = dp[i-1][j-1]。
  • 如果 word1[i-1] 和 word2[j-1] 不同,则说明需要进行插入、删除或替换操作,需要选取其中的最小值,因此 dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1。

最终的结果是 dp[m][n],其中 m 和 n 分别为两个字符串的长度。

例如,对于字符串 "horse" 和 "ros",使用上述代码可以得到编辑距离为 3,与之前的例子相同。

需要注意的是,编辑距离问题的时间复杂度是 O(mn),其中 m 和 n 分别为两个字符串的长度。如果字符串长度非常大,可以考虑使用空间复杂度更小的滚动数组或矩阵压缩技巧来优化算法。

powered by Gitbook© 2023 编外计划 | 最后修改: 2023-11-24 03:37:00

results matching ""

    No results matching ""