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 数组的递推关系,即如果字符相等,则操作数不变;如果字符不等,则取插入、删除、替换三种操作中的最小操作数加一。

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

相关推荐
不是二师兄的八戒14 分钟前
本地 PHP 和 Java 开发环境 Docker 化与配置开机自启
java·docker·php
爱编程的小生26 分钟前
Easyexcel(2-文件读取)
java·excel
带多刺的玫瑰43 分钟前
Leecode刷题C语言之统计不是特殊数字的数字数量
java·c语言·算法
爱敲代码的憨仔1 小时前
《线性代数的本质》
线性代数·算法·决策树
熬夜学编程的小王1 小时前
【C++篇】深度解析 C++ List 容器:底层设计与实现揭秘
开发语言·数据结构·c++·stl·list
yigan_Eins1 小时前
【数论】莫比乌斯函数及其反演
c++·经验分享·算法
阿史大杯茶1 小时前
AtCoder Beginner Contest 381(ABCDEF 题)视频讲解
数据结构·c++·算法
计算机毕设指导61 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
Gu Gu Study1 小时前
枚举与lambda表达式,枚举实现单例模式为什么是安全的,lambda表达式与函数式接口的小九九~
java·开发语言
Chris _data1 小时前
二叉树oj题解析
java·数据结构