编辑距离

时间:2022-07-22
本文章向大家介绍编辑距离,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

问题描述

给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

插入一个字符 删除一个字符 替换一个字符

示例 1:

输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')
示例 2:

输入:word1 = "intention", word2 = "execution"
输出:5
解释:
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/edit-distance
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

递归方案

我们可以从两个单词的最后一个字母开始比较,两单词的最后一个字母分别记做word1[i], word2[j]。

若word1[i] 等于word2[j],i 、 j 前移 ,只需比较他们之前的元素 word1[i - 1], word[j - 1]情况;

不相等时有以下三种解决策略:

1)将word2[j]插入到word1[i]之后,只用判断word1[ i ] 和 word2[ j - 1 ]的情况

2)将word1[i]删除了,只用考虑word1[ i - 1] 和 word2[ j ]的情况

3)将word1[i]替换为word2[j], 后续只用考虑word1[i - 1] 和 word2[j - 1]情况

定义fun(i,j)表示word1前 i - 1个元素转化为 word2的前j - 1个元素所需的最少操作次数。

fun(i,j) = begin{cases}fun(i - 1, j - 1) qquad qquad qquadqquadqquadqquad word1[i] = word2[j]\ min(fun(i, j - 1), fun(i - 1, j), fun(i - 1, j - 1)) + 1 quad elseend{cases}

不相等时选择三种修改中操作数最少的那个,实现代码如下:

class Solution {
    public int minDistance(String word1, String word2) {
        return fun(word1.length() - 1, word2.length() - 1, word1, word2);
    }
    public int fun(int i, int j, String word1, String word2){
        if(i == -1){
            return j + 1;
        }
        if(j == -1){
            return i + 1;
        }
        if(word1.charAt(i) == word2.charAt(j)){
            return fun(i - 1, j - 1, word1, word2);
        }
        return Math.min(fun(i, j - 1, word1, word2), 
        Math.min(fun(i - 1, j, word1, word2), fun(i - 1, j - 1, word1, word2) ) ) + 1;
    }
}

动态规划

递归方案超时了,改动态规划咯。

我们由递归方案可以得到,其转移函数与低归方案相同,此外我们dp[i] [j]的取值只依赖其上边,左边,左上三个位置的值。因此我们可以依次从上至下,从左至右填表。

为了简化baseline,定义二维整型数组dp,dp[i] [j] 表示word1前 i 个元素转化为 word2的前j 个元素所需的最少操作次数。baseline如下:

dp[i][0] = i\ dp[0][j] = j

转移方程如下:

dp[i][j] = begin{cases}dp[i - 1][j - 1] qquadqquadqquad word1[i - 1] = word2[j - 1]\ min(dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]) + 1 quad elseend{cases}

实现代码如下:

class Solution {
    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];
    }
}