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

【LeetCode 热题 100】1143. 最长公共子序列——(解法二)递推

Problem: 1143. 最长公共子序列

文章目录

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

整体思路

这段代码同样旨在解决 “最长公共子序列” (LCS) 问题,但它采用的是一种 自底向上(Bottom-Up)的动态规划 方法,也称为 迭代法制表法 (Tabulation)。这种方法通过构建一个DP表(dp 二维数组),从最小的子问题开始,逐步计算出最终的解,避免了递归的开销。

该实现是解决LCS问题的标准教科书式DP模型。

  1. 状态定义与索引映射

    • 算法定义了一个二维DP数组 dp,大小为 (m+1) x (n+1)
    • dp[i][j] 的含义是:text1 的前 i 个字符(text1.substring(0, i))与 text2 的前 j 个字符(text2.substring(0, j))的最长公共子序列的长度。
    • 这是一个常见的索引偏移技巧。dp 数组的索引 ij 分别对应了 text1text2长度,而字符串的索引是 i-1j-1。这样做的好处是,dp 数组的第0行和第0列可以天然地代表空字符串的情况,简化了边界处理。
  2. 基础情况 (Base Case)

    • 在Java中,new int[m + 1][n + 1] 数组的所有元素默认初始化为0。
    • dp[0][j]dp[i][0] 始终为0。这恰好满足我们的基础情况:任何字符串与一个空字符串的最长公共子序列长度都为0。
  3. 状态转移 (State Transition)

    • 算法使用两层嵌套循环来填充DP表。ij 在循环中对应的是字符串的索引。
    • 在循环的每一步,计算 dp[i+1][j+1] 的值,它代表 text1[0...i]text2[0...j] 的LCS长度。
    • 状态转移逻辑基于对 text1.charAt(i)text2.charAt(j) 的比较:
      a. 如果 text1.charAt(i) == text2.charAt(j)
      • 这意味着这两个相同的字符可以被包含在LCS中。
      • 因此,当前LCS的长度等于 text1[0...i-1]text2[0...j-1] 的LCS长度再加1。
      • 状态转移方程为:dp[i + 1][j + 1] = dp[i][j] + 1
        b. 如果 text1.charAt(i) != text2.charAt(j)
      • 这意味着这两个不同的字符不可能同时被包含在LCS中。
      • LCS的长度取决于两种可能中较长的那一个:
        1. text1[0...i-1]text2[0...j] 的LCS,其长度为 dp[i][j+1]
        2. text1[0...i]text2[0...j-1] 的LCS,其长度为 dp[i+1][j]
      • 状态转移方程为:dp[i + 1][j + 1] = Math.max(dp[i][j + 1], dp[i + 1][j])
  4. 返回结果

    • 当所有循环结束后,dp 数组已经完全填充。我们需要的最终答案,即 text1text2 整个字符串的LCS长度,就存储在 dp[m][n] 中。

完整代码

class Solution {/*** 计算两个字符串的最长公共子序列的长度。* @param text1 第一个字符串* @param text2 第二个字符串* @return 最长公共子序列的长度*/public int longestCommonSubsequence(String text1, String text2) {int m = text1.length();int n = text2.length();// dp[i][j]: 表示 text1 的前 i 个字符与 text2 的前 j 个字符的 LCS 长度。// 使用 m+1, n+1 的大小是为了用第0行和第0列代表空字符串,简化边界处理。int[][] dp = new int[m + 1][n + 1];// i 和 j 是 text1 和 text2 的 0-based 索引for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {// 如果当前比较的两个字符相同if (text1.charAt(i) == text2.charAt(j)) {// LCS 长度等于它们各自去掉末尾字符后的 LCS 长度 + 1。dp[i + 1][j + 1] = dp[i][j] + 1;} else {// 如果字符不同,LCS 长度等于两种情况中的较大值:// 1. text1 去掉末尾 vs text2 (dp[i][j+1])// 2. text1 vs text2 去掉末尾 (dp[i+1][j])dp[i + 1][j + 1] = Math.max(dp[i][j + 1], dp[i + 1][j]);}}}// 最终答案存储在 dp[m][n] 中,代表整个 text1 和 text2 的 LCS 长度。return dp[m][n];}
}

时空复杂度

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

  • mtext1 的长度,ntext2 的长度。
  1. 循环结构:算法使用了两层嵌套的 for 循环。
    • 外层循环从 i = 0 运行到 m-1,执行 m 次。
    • 内层循环从 j = 0 运行到 n-1,执行 n 次。
  2. 计算依据
    • 总的操作次数(主要是比较、加法和Math.max)是内外层循环次数的乘积,即 m * n

综合分析
算法的时间复杂度为 O(m * n)

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

  1. 主要存储开销:算法创建了一个名为 dp 的二维整型数组来存储动态规划的所有中间状态。
  2. 空间大小:该数组的大小是 (m + 1) * (n + 1)

综合分析
算法所需的额外空间主要由 dp 数组决定,其空间复杂度为 O(m * n)

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

相关文章:

  • 2025 大学生职业准备清单:从数据到财会,这些核心证书值得考
  • 【IO】多进程编程课后练习
  • 单多行文本溢出
  • Selenium核心技巧:元素定位与等待策略
  • ArkUI核心功能组件使用
  • 【线段树】3525. 求出数组的 X 值 II|2645
  • Spring 事务原理解析:AOP 的一次完美落地
  • 深度学习——基于卷积神经网络实现食物图像分类【4】(使用最优模型)
  • 广度优先搜索(BFS, Breadth-First Search)
  • 数字化转型的六大天问:你的项目为何失败
  • 数据开发工作了一年,准备跳槽,回顾一些面试常见问题,大数据面试题汇总与答案分享
  • 【3D打印】3D打印机首次使用心得
  • 2025最新“Java 面试八股文 + 各大厂的面试真题”限时开源
  • 人工智能助力流感疫苗选择:MIT 团队推出 VaxSeer 系统
  • Understanding the Flap T in American English
  • 开源企业级快速开发平台(JeecgBoot)
  • Python闭包机制:原理、应用与安全防护
  • 【Doris入门】Doris数据表模型:聚合模型(Aggregate Key Model)详解
  • java-设计模式-4-创建型模式-工厂
  • 【52页PPT】服务业数字化转型如何做(附下载方式)
  • Ubuntu 用户和用户组
  • X86、X64 与 ARM:架构的剖析与比较
  • webpack性能优化指南
  • MacOS - 记录MacOS发烫的好几天 - 幕后黑手竟然是
  • 神经网络|(十八)概率论基础知识-伽马函数溯源-阶乘的积分表达式
  • k8s常用命令
  • 对矩阵行化简操作几何含义的理解
  • HDI是什么?与普通线路板有何区别?优势在哪?
  • 嵌入式git分支管理策略
  • Java基础第9天总结(可变参数、Collections、斗地主)