LeetCode题练习与总结:编辑距离--72

一、题目描述

给你两个单词 word1word2请返回将 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')

提示:

  • 0 <= word1.length, word2.length <= 500
  • word1word2 由小写英文字母组成

二、解题思路

定义一个二维数组 dp,其中 dp[i][j] 表示将 word1 的前 i 个字符转换为 word2 的前 j 个字符所需要的最少操作数。对于 dp 数组的每一个元素,我们可以根据以下情况来更新它的值:

  1. 如果 word1[i] == word2[j],则 dp[i][j] = dp[i-1][j-1],因为当前字符匹配,所以不需要任何操作,直接继承前面的结果。

  2. 如果 word1[i] != word2[j],则 dp[i][j] 可以通过以下三种操作之一得到:

  • 插入一个字符:dp[i][j] = dp[i][j-1] + 1,相当于将 word2[j] 插入到 word1 中。
  • 删除一个字符:dp[i][j] = dp[i-1][j] + 1,相当于将 word1[i] 删除。
  • 替换一个字符:dp[i][j] = dp[i-1][j-1] + 1,相当于将 word1[i] 替换为 word2[j]
  • 在这三种操作中,我们选择操作数最少的一种。

初始化 dp 数组时,dp[0][j] 表示将一个空字符串转换为 word2 的前 j 个字符所需要的操作数,显然为 j;同理,dp[i][0] 表示将 word1 的前 i 个字符转换为空字符串所需要的操作数,显然为 i

三、具体代码

java 复制代码
class Solution {
    public int minDistance(String word1, String word2) {
        int m = word1.length();
        int n = word2.length();
        
        // dp[i][j] 表示将 word1 的前 i 个字符转换为 word2 的前 j 个字符所需要的最少操作数
        int[][] dp = new int[m + 1][n + 1];
        
        // 初始化 dp 数组
        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(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
                }
            }
        }
        
        // 返回最终结果
        return dp[m][n];
    }
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 我们有一个双层循环,分别遍历字符串 word1 和 word2 的所有字符。
  • 外层循环遍历 word1 的每个字符,共有 m 次迭代(其中 m 是 word1 的长度)。
  • 内层循环遍历 word2 的每个字符,共有 n 次迭代(其中 n 是 word2 的长度)。
  • 在循环的每次迭代中,我们执行的是常数时间的操作,即比较字符、更新动态规划数组。
  • 因此,总的时间复杂度是 O(m * n),即两个字符串长度的乘积。
2. 空间复杂度
  • 我们定义了一个二维数组 dp,其大小为 (m + 1) * (n + 1),其中 m 和 n 分别是字符串 word1 和 word2 的长度。
  • 这个二维数组用于存储从 word1 的前 i 个字符转换到 word2 的前 j 个字符所需的最少操作数。
  • 因此,空间复杂度也是 O(m * n),即两个字符串长度的乘积。

五、总结知识点

1. 动态规划(Dynamic Programming, DP):

  • 动态规划是一种算法设计技术,用于求解具有重叠子问题和最优子结构特性的复杂问题。
  • 它将问题分解为较小的子问题,并存储这些子问题的解,以避免重复计算。
  • 在本问题中,dp[i][j] 表示将 word1 的前 i 个字符转换为 word2 的前 j 个字符所需要的最少操作数。

2. 二维数组:

  • 二维数组是一种数据结构,用于存储多个相同类型的元素,这些元素以行和列的形式排列。
  • 在本问题中,dp 是一个二维数组,用于存储不同子问题的解。

3. 字符串操作:

  • charAt(int index) 方法用于获取字符串中指定索引处的字符。
  • 在本问题中,使用 charAt(i - 1) 来获取 word1 和 word2 字符串中的字符,因为数组的索引从 0 开始,而 dp 数组的维度是从 1 开始的。

4. 数学函数:

  • Math.min() 函数用于在多个值中选择最小值。
  • 在本问题中,使用 Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) 来确定在当前字符不匹配时,进行插入、删除或替换操作中的最小操作数。

5. 循环结构:

  • 使用了双层循环来遍历 word1 和 word2 的所有字符组合,以填充 dp 数组。

6. 边界条件处理:

  • 使用了单独的循环来初始化 dp 数组的边界条件,即当其中一个字符串为空时,转换为另一个字符串所需的操作数。

7. 递推关系:

  • 通过比较当前字符是否相等,定义了 dp 数组的递推关系,即如果字符相等,则操作数不变;如果字符不等,则取插入、删除、替换三种操作中的最小操作数加一。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

相关推荐
迷迭所归处2 分钟前
C++ —— 关于vector
开发语言·c++·算法
架构文摘JGWZ31 分钟前
Java 23 的12 个新特性!!
java·开发语言·学习
leon62532 分钟前
优化算法(一)—遗传算法(Genetic Algorithm)附MATLAB程序
开发语言·算法·matlab
CV工程师小林32 分钟前
【算法】BFS 系列之边权为 1 的最短路问题
数据结构·c++·算法·leetcode·宽度优先
Navigator_Z1 小时前
数据结构C //线性表(链表)ADT结构及相关函数
c语言·数据结构·算法·链表
还听珊瑚海吗1 小时前
数据结构—栈和队列
数据结构
Aic山鱼1 小时前
【如何高效学习数据结构:构建编程的坚实基石】
数据结构·学习·算法
拾光师1 小时前
spring获取当前request
java·后端·spring
aPurpleBerry1 小时前
neo4j安装启动教程+对应的jdk配置
java·neo4j
天玑y1 小时前
算法设计与分析(背包问题
c++·经验分享·笔记·学习·算法·leetcode·蓝桥杯