当前位置: 首页 > news >正文

【LeetCode 热题 100】72. 编辑距离——(解法一)记忆化搜索

Problem: 72. 编辑距离

文章目录

  • 整体思路
  • 完整代码
  • 时空复杂度
    • 时间复杂度:O(m * n)
    • 空间复杂度:O(m * n)

整体思路

这段代码旨在解决经典的 “编辑距离” (Edit Distance) 问题,也称为 莱文斯坦距离 (Levenshtein Distance)。问题要求计算将一个字符串 word1 转换为另一个字符串 word2 所需的最少操作次数。允许的操作有三种:插入一个字符、删除一个字符、替换一个字符。

该算法采用的是一种 自顶向下(Top-Down)的动态规划 方法,即 记忆化搜索 (Memoization)。它将两个长字符串的编辑距离问题,分解为它们各种前缀之间的编辑距离子问题,并通过递归解决,同时使用一个二维数组来缓存已解决的子问题的答案,以避免重复计算。

算法的核心逻辑如下:

  1. 问题分解与递归关系

    • 算法的核心思想是比较两个字符串的末尾字符。
    • 我们定义一个函数 dfs(i, j),其含义是 “word1 的前 i+1 个字符(word1[0...i])与 word2 的前 j+1 个字符(word2[0...j])之间的最小编辑距离”。
    • 对于 dfs(i, j),有两种情况:
      a. 末尾字符相同 (w1[i] == w2[j]):如果两个字符串的最后一个字符相同,那么我们不需要对这两个字符进行任何操作。问题直接简化为计算它们各自去掉末尾字符后的编辑距离,即 dfs(i-1, j-1)
      b. 末尾字符不同 (w1[i] != w2[j]):如果最后一个字符不同,我们必须执行一次操作才能使它们匹配。有三种选择,我们取其中成本最小的:
      • 替换 (Replace):将 w1[i] 替换为 w2[j]。操作后末尾字符匹配,问题变为计算 word1[0...i-1]word2[0...j-1] 的距离。成本是 1 + dfs(i-1, j-1)
      • 删除 (Delete):删除 w1[i]。问题变为计算 word1[0...i-1]word2[0...j] 的距离。成本是 1 + dfs(i-1, j)
      • 插入 (Insert):在 w1 末尾插入 w2[j]。问题变为计算 w1[0...i]w2[0...j-1] 的距离。成本是 1 + dfs(i, j-1)
        因此,dfs(i, j) = 1 + min(dfs(i-1, j-1), dfs(i-1, j), dfs(i, j-1))
  2. 记忆化 (Memoization)

    • 纯粹的递归会导致子问题被大量重复计算,效率极低。
    • 算法使用二维 memo 数组存储 dfs(i, j) 的计算结果。在函数开头检查 memo,如果已计算,直接返回结果。
  3. 基础情况 (Base Cases)

    • if (i < 0): word1 为空串。要将其转换成 word2[0...j],需要 j+1 次插入操作。
    • if (j < 0): word2 为空串。要将 word1[0...i] 转换成空串,需要 i+1 次删除操作。

完整代码

import java.util.Arrays;class Solution {private char[] w1;private char[] w2;private int[][] memo;/*** 计算将 word1 转换成 word2 所使用的最少操作数。* @param word1 第一个单词* @param word2 第二个单词* @return 最小编辑距离*/public int minDistance(String word1, String word2) {w1 = word1.toCharArray();w2 = word2.toCharArray();int m = w1.length;int n = w2.length;// memo: 记忆化数组。memo[i][j] 存储 dfs(i, j) 的结果。memo = new int[m][n];// 初始化 memo 数组为 -1,表示所有子问题都尚未计算。for (int[] row : memo) {Arrays.fill(row, -1);}// 从两个字符串的末尾开始,自顶向下进行递归求解。return dfs(m - 1, n - 1);}/*** 记忆化搜索函数。* @param i      word1 的当前末尾字符索引* @param j      word2 的当前末尾字符索引* @return word1[0...i] 和 word2[0...j] 的最小编辑距离*/private int dfs(int i, int j) {// 基础情况:如果 word1 的前缀为空串if (i < 0) {// 需要 j+1 次插入操作才能变成 word2 的前缀return j + 1;}// 基础情况:如果 word2 的前缀为空串if (j < 0) {// 需要 i+1 次删除操作才能变成空串return i + 1;}// 记忆化检查:如果该子问题已计算过,直接返回。if (memo[i][j] != -1) {return memo[i][j];}// 状态转移:// 如果当前比较的两个字符相同if (w1[i] == w2[j]) {// 无需操作,距离等于它们各自去掉末尾字符后的距离。return memo[i][j] = dfs(i - 1, j - 1);}// 如果字符不同,必须执行一次操作。// 在 插入、删除、替换 三种操作中选择成本最小的一种。// dfs(i, j-1):   对应插入操作// dfs(i-1, j):   对应删除操作// dfs(i-1, j-1): 对应替换操作return memo[i][j] = Math.min(Math.min(dfs(i, j - 1), dfs(i - 1, j)), dfs(i - 1, j - 1)) + 1;}
}

时空复杂度

时间复杂度:O(m * n)

  • mword1 的长度,nword2 的长度。
  1. 状态数量:由于记忆化的存在,每个状态 (i, j) 只会被实际计算一次。
    • i 的范围是从 0m-1
    • j 的范围是从 0n-1
    • 因此,总的状态数量是 m * n
  2. 每个状态的计算时间:在 dfs 函数内部,除了递归调用,其他的操作都是 O(1) 的。

综合分析
总的时间复杂度等于(状态数量)×(每个状态的计算时间),即 O(m * n)。记忆化将算法从指数级 O(3^(m+n)) 优化到了多项式级。

空间复杂度:O(m * n)

  1. 记忆化数组:算法创建了一个 memo 二维数组来存储所有子问题的解。其大小为 m * n。这部分空间占用为 O(m * n)
  2. 递归调用栈:递归的深度也需要考虑。在最坏的情况下,例如 dfs(m-1, n-1) 一路调用 dfs(m-2, n-2) 直到基础情况,递归深度可达 m+n。因此,递归栈所占用的空间是 O(m + n)

综合分析
算法所需的总空间是 O(m * n) (用于 memo 数组) + O(m + n) (用于递归栈)。由于 m*n 是主导项,因此最终的空间复杂度为 O(m * n)

http://www.xdnf.cn/news/1440019.html

相关文章:

  • DBSCAN 密度聚类分析算法
  • 【ProtoBuf 】C++ 网络通讯录开发实战:ProtoBuf 协议设计与 HTTP 服务实现
  • 构建下一代互联网:解码Web3、区块链、协议与云计算的协同演进
  • 【微信小程序预览文件】(PDF、DOC、DOCX、XLS、XLSX、PPT、PPTX)
  • 机器学习进阶,一文搞定模型选型!
  • 智能高效内存分配器测试报告
  • 根据fullcalendar实现企业微信的拖动式预约会议
  • Linux 用户的 Windows 改造之旅
  • Web端最强中继器表格元件库来了!55页高保真交互案例,Axure 9/10/11通用
  • 使用langgraph创建工作流系列3:增加记忆
  • 100种高级数据结构 (速查表)
  • 【NVIDIA B200】1.alltoall_perf 单机性能深度分析:基于 alltoall_perf 测试数据
  • 如何评价2025年数学建模国赛?
  • Debezium系列之:Flink SQL消费Debezium数据,只消费新增数据,过滤掉更新、删除数据
  • 计算机毕业设计选题推荐:基于Python+Django的新能源汽车数据分析系统
  • AI随笔番外 · 猫猫狐狐的尾巴式技术分享
  • Networking Concepts
  • 超越马力欧:如何为经典2D平台游戏注入全新灵魂
  • vue 手动书写步骤条
  • 用Blender制作Rat Rod风格汽车
  • MySQL 8.0.40 主从复制完整实验总结(基础搭建 + 进阶延时同步与误操作恢复)
  • 智能电视小米电视浏览器兼容性踩坑电视黑屏或者电视白屏,Vue项目从Axios到Fetch的避坑指南
  • GitHub每日最火火火项目(9.3)
  • 演员-评论员算法有何优点?
  • 《探索C++11:现代语法的性能优化策略(中篇)》
  • 从公共形象到专属定制,井云交互数字人满足金融/政务多元需求
  • etcd对比redis
  • MySQL--CRUD
  • Oracle 10g 安装教程(详解,从exe安装到数据库配置,附安装包)​
  • 食物分类案例优化改进 (数据增强,最优模型保存和使用)