力扣第 72 题 编辑距离

news/2024/11/30 0:23:26/

一、题目描述

给你两个单词 word1word2,请返回将 word1 转换为 word2 所使用的最少操作数。

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

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

二、解题思路

1. 问题分析

  • 这是一个最优子结构问题,适合用动态规划解决。
  • 假设将 word1 转换成 word2 的最少操作数为 dp[i][j],表示将 word1[0...i-1] 转换成 word2[0...j-1] 的最小编辑距离。

2. 状态转移方程

  1. 如果 word1[i-1] == word2[j-1]
    • 当前字符相同,不需要操作,dp[i][j] = dp[i-1][j-1]
  2. 如果 word1[i-1] != word2[j-1]
    • 可以进行三种操作,选择操作数最小的一种:
      • 插入字符:dp[i][j] = dp[i][j-1] + 1
      • 删除字符:dp[i][j] = dp[i-1][j] + 1
      • 替换字符:dp[i][j] = dp[i-1][j-1] + 1

3. 边界条件

  • i == 0 时,dp[i][j] = j,表示将空字符串转换为 word2[0...j-1] 需要插入 j 个字符。
  • j == 0 时,dp[i][j] = i,表示将 word1[0...i-1] 转换为空字符串需要删除 i 个字符。

三、代码实现

动态规划实现(C语言)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>int min(int a, int b, int c) {int minVal = a < b ? a : b;return minVal < c ? minVal : c;
}int minDistance(char *word1, char *word2) {int m = strlen(word1);int n = strlen(word2);// 创建 DP 数组int **dp = (int **)malloc((m + 1) * sizeof(int *));for (int i = 0; i <= m; i++) {dp[i] = (int *)malloc((n + 1) * sizeof(int));}// 初始化边界for (int i = 0; i <= m; i++) {dp[i][0] = i;}for (int j = 0; j <= n; j++) {dp[0][j] = j;}// 填充 DP 表for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {if (word1[i - 1] == word2[j - 1]) {dp[i][j] = dp[i - 1][j - 1];} else {dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;}}}// 最终结果int result = dp[m][n];// 释放内存for (int i = 0; i <= m; i++) {free(dp[i]);}free(dp);return result;
}int main() {char word1[100], word2[100];printf("请输入第一个单词:");scanf("%s", word1);printf("请输入第二个单词:");scanf("%s", word2);int result = minDistance(word1, word2);printf("最小编辑距离为:%d\n", result);return 0;
}

这段代码的作用是更新二维动态规划数组 dp 的值,根据三种可能的操作选择最优解。我们逐项解释:


上下文:动态规划的含义

  • dp[i][j] 表示将 word1[0...i-1] 转换为 word2[0...j-1] 的最小操作数。
  • word1[i-1] != word2[j-1] 的情况下,当前状态 dp[i][j] 的值需要通过三种操作之一得到:
    1. 插入操作:将 word2[j-1] 插入到 word1[0...i-1] 中;
    2. 删除操作:将 word1[i-1]word1[0...i-1] 中删除;
    3. 替换操作:将 word1[i-1] 替换为 word2[j-1]

具体公式分析

dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;
三个子问题:
  1. 删除操作
    如果选择删除 word1[i-1],只需要考虑将 word1[0...i-2] 转换为 word2[0...j-1] 的最优解,然后加 1(删除操作的代价):
    [
    dp[i][j] = dp[i-1][j] + 1
    ]

  2. 插入操作
    如果选择插入 word2[j-1],只需要考虑将 word1[0...i-1] 转换为 word2[0...j-2] 的最优解,然后加 1(插入操作的代价):
    [
    dp[i][j] = dp[i][j-1] + 1
    ]

  3. 替换操作
    如果选择将 word1[i-1] 替换为 word2[j-1],只需要考虑将 word1[0...i-2] 转换为 word2[0...j-2] 的最优解,然后加 1(替换操作的代价):
    [
    dp[i][j] = dp[i-1][j-1] + 1
    ]

最优选择

我们取三种操作中最小的代价:
[
dp[i][j] = \min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1}) + 1
]


特殊情况:当 word1[i-1] == word2[j-1]

如果当前字符相等,不需要任何操作,dp[i][j] = dp[i-1][j-1]


示例分析

示例 1:

word1 = "horse", word2 = "ros"

填表过程

ros
0123
h1123
o2212
r3222
s4332
e5443

最终结果为 dp[5][3] = 3


示例 2:

word1 = "intention", word2 = "execution"

填表可以类似完成,逐步根据状态转移公式填充每个 dp[i][j] 的值。


四、复杂度分析

时间复杂度

  • 填充一个大小为 m × n m \times n m×n 的 DP 表,其中 m = len(word1) m = \text{len(word1)} m=len(word1) n = len(word2) n = \text{len(word2)} n=len(word2)
  • 总时间复杂度为 O ( m × n ) O(m \times n) O(m×n)

空间复杂度

  • DP 表占用 O ( m × n ) O(m \times n) O(m×n) 的空间。
  • 如果进一步优化,可以使用滚动数组将空间复杂度优化为 O ( min ⁡ ( m , n ) ) O(\min(m, n)) O(min(m,n))

五、运行示例

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

http://www.ppmy.cn/news/1551039.html

相关文章

Chrome://常用的内部页面地址

Chrome浏览器提供了一系列特殊的内部页面来用于开发和调试&#xff0c;可以通过在地址栏中输入以chrome://开头的协议来访问。 这些页面用于各种高级设置、实验性功能、诊断信息和浏览器工具等。 一些常用的内部页面&#xff1a; 协议用途chrome://settings/打开Chrome的设置…

量化交易系统开发-实时行情自动化交易-8.1.TradingView平台

19年创业做过一年的量化交易但没有成功&#xff0c;作为交易系统的开发人员积累了一些经验&#xff0c;最近想重新研究交易系统&#xff0c;一边整理一边写出来一些思考供大家参考&#xff0c;也希望跟做量化的朋友有更多的交流和合作。 接下来会对于TradingView平台介绍。 T…

C# 常量

文章目录 前言一、整数常量&#xff08;一&#xff09;合法与非法实例对比&#xff08;二&#xff09;不同进制及类型示例 二、浮点常量三、字符常量四、字符串常量五、定义常量 前言 在 C# 编程的世界里&#xff0c;常量是一类特殊的数据元素&#xff0c;它们如同程序中的 “定…

SpringBoot连接测试InfluxDB时序数据库

1&#xff09;创建一个Springboot项目&#xff0c;在pom.xml引入influxDB相关的包 <!-- influxdb --><dependency><groupId>org.jetbrains.kotlin</groupId><artifactId>kotlin-stdlib</artifactId><version>1.8.10</version>…

【ANC系统】主动噪声控制系统结构分类

1. 根据是否获取参考信号划分 前馈 ANC 系统&#xff08;Feedforward ANC&#xff09; 原理&#xff1a;前馈 ANC 系统的基本工作原理是利用参考信号来生成反噪声。参考信号通常是由传感器检测到的“初级噪声”信号&#xff0c;系统在噪声发生之前就进行干预。参考信号通常是直…

从 App Search 到 Elasticsearch — 挖掘搜索的未来

作者&#xff1a;来自 Elastic Nick Chow App Search 将在 9.0 版本中停用&#xff0c;但 Elasticsearch 拥有你构建强大的 AI 搜索体验所需的一切。以下是你需要了解的内容。 生成式人工智能的最新进展正在改变用户行为&#xff0c;激励开发人员创造更具活力、更直观、更引人入…

Git工作原理与常用方法汇总

Git的工作原理 Git是一种分布式版本控制系统&#xff0c;其工作原理包括以下几个关键步骤&#xff1a; 工作区&#xff08;Working Directory&#xff09;&#xff1a;你在本地的项目目录&#xff0c;包含所有项目文件。暂存区&#xff08;Staging Area&#xff09;&#xff…

天锐绿盾加密软件与Ping32联合打造企业级安全保护系统,确保敏感数据防泄密与加密管理

随着信息技术的飞速发展&#xff0c;企业在日常经营过程中产生和处理的大量敏感数据&#xff0c;面临着越来越复杂的安全威胁。尤其是在金融、医疗、法律等领域&#xff0c;数据泄漏不仅会造成企业巨大的经济损失&#xff0c;还可能破坏企业的信誉和客户信任。因此&#xff0c;…