正在加载今日诗词....
3 min read

LeetCode72 编辑距离

LeetCode 字符串算法之 编辑距离
LeetCode72 编辑距离

编辑距离

Difficulty: 困难

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

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

  1. 插入一个字符
  2. 删除一个字符
  3. 替换一个字符

示例 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')

思路

动态规划

动态规划的状态定义 dp[i][j] , 其中ij都是各自字符串的终止字符的长度,不是索引

初始值

m\n # H O R S E
# 0 1 2 3 4 5
R 1
O 2
S 3

动态迁移方程

 dp[i][j] = dp[i-1][j-1]; // word1[i-1] == word2[j-1]
                    
 dp[i][j] = min(min(dp[i][j-1],dp[i-1][j]),
                    dp[i-1][j-1]) + 1; // word1[i-1] != word2[j-1]

Solution

Language: C++

// 动态规划 , 划分子问题 -> 求解更大的问题
// 对于字符串的处理, 两个字符串: 有从尾部两两比较, 有从头两两比较 ;单字符串 从头,从尾,从中间处理
class Solution {
public:
    int minDistance(string word1, string word2) {
        int m = word1.size();
        int n = word2.size();
        // 小技巧判断
        if (m * n == 0) return n + m;
        // 1. 动态规划 的 状态定义 dp[i][j] , 其中i与j都是各自字符串的终止字符的长度,不是索引
        // 两个字符串 word1[0-(i-1)] 与 word2[0-(j-1)] 的编辑距离 , 因为是长度,计算索引要用 长度-1
        vector<vector<int>> dp(m+1,vector<int>(n+1,0));
        // 从底向上推算
        // 2. 初始化 状态的初始值
        // 2.1 word1 为空时
        for (int i =0; i <= m;i++) {
            dp[i][0] = i;
        }
        // 2.2 word2 为空时
        for (int i = 0; i <= n;i++) {
            dp[0][i] = i;
        }

        // 3. 根据动态迁移方程更新状态
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j<= n; j++) {
                // 因为 i/j 代表的是长度, 所以 比较字符的时候要 -1
                if (word1[i-1] == word2[j-1]) {
                    // 单词末尾相等, 则当前不需要更改
                    // 编辑距离等于两个word都缩减i,j字符后的距离
                    dp[i][j] = dp[i-1][j-1];
                } else {
                    // 根据描述可以知道, i,j 字符不同时, 编辑的操作有下面几种, 这里是重点
                    // dp[i][j-1] word2 删除(j-1)索引下标的字符,重新比较
                    // dp[i-1][j] word2 插入一个[j]索引的字符, 重新比较
                    // dp[i-1][j-1] word2 替换一个[j-1]的字符, 重新比较
                    // 因为上面的步骤都是编辑了一次, 所有 dp[i][j] 的值是 小问题的编辑距离 +1
                    dp[i][j] = min(min(dp[i][j-1],dp[i-1][j]),
                    dp[i-1][j-1]) + 1;
                }
            }
        }
        // 4. 返回最后的值
        return dp[m][n] ;
    }
};