数据结构与算法-最长公共子序列

数据结构与算法-最长公共子序列

大家好,欢迎回到我们的算法学习系列。今天,我们将探讨一个经典的动态规划问题——最长公共子序列(Longest Common Subsequence,简称 LCS)。这个问题在字符串处理和比较中非常常见。

什么是最长公共子序列?

最长公共子序列是指在两个序列中,按照顺序出现但不一定连续出现的最长子序列。例如,字符串 ABCBDABBDCABA 的最长公共子序列是 BCBABDAB,长度为 4。

问题描述

给定两个字符串 text1text2,返回这两个字符串的最长公共子序列的长度。

示例

  • 输入:text1 = "abcde", text2 = "ace"
    输出:3(最长公共子序列是 “ace”)
  • 输入:text1 = "abc", text2 = "abc"
    输出:3(最长公共子序列是 “abc”)

解决思路

我们可以使用动态规划(Dynamic Programming)来解决这个问题。动态规划通过将问题分解为子问题,并将子问题的结果存储起来,以便后续计算使用,从而提高效率。

动态规划的步骤

  1. 定义状态:定义一个二维数组 dp,其中 dp[i][j] 表示字符串 text1 的前 i 个字符与字符串 text2 的前 j 个字符的最长公共子序列长度。
  2. 初始化:初始化 dp 数组的第一行和第一列,因为如果一个字符串是空串,则最长公共子序列的长度为 0。
  3. 状态转移:对于每个字符 text1[i-1]text2[j-1]
    • 如果 text1[i-1] == text2[j-1],则 dp[i][j] = dp[i-1][j-1] + 1
    • 否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1])
  4. 返回结果dp[m][n] 即为 text1text2 的最长公共子序列长度,其中 mn 分别是 text1text2 的长度。

实现代码

下面是用 JavaScript 实现的最长公共子序列算法:

function longestCommonSubsequence(text1, text2) {
  const m = text1.length;
  const n = text2.length;
  const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));

  for (let i = 1; i <= m; i++) {
    for (let j = 1; j <= n; j++) {
      if (text1[i - 1] === text2[j - 1]) {
        dp[i][j] = dp[i - 1][j - 1] + 1;
      } else {
        dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
      }
    }
  }

  return dp[m][n];
}

代码解析

  1. 初始化二维数组:创建一个大小为 (m+1) x (n+1) 的二维数组 dp,并初始化为 0。
  2. 双重循环遍历:使用双重循环遍历字符串 text1text2 的每个字符。
  3. 状态转移
    • 如果字符相同,则 dp[i][j] = dp[i-1][j-1] + 1
    • 如果字符不同,则 dp[i][j] = max(dp[i-1][j], dp[i][j-1])
  4. 返回结果dp[m][n] 即为两个字符串的最长公共子序列长度。

图解

让我们通过图解来理解动态规划的过程:

假设 text1 = "abcde"text2 = "ace"

初始化 dp 数组:

  '' a b c d e
'' 0 0 0 0 0 0
a  0 0 0 0 0 0
c  0 0 0 0 0 0
e  0 0 0 0 0 0

填充 dp 数组:

  '' a b c d e
'' 0 0 0 0 0 0
a  0 1 1 1 1 1
c  0 1 1 2 2 2
e  0 1 1 2 2 3

最终结果 dp[5][3] = 3,即最长公共子序列的长度为 3。

小结

今天,我们学习了最长公共子序列算法的原理、实现方法和应用场景。通过动态规划的方法,我们可以高效地求解两个字符串的最长公共子序列长度,这在字符串处理和比较中非常常用。

感谢大家的阅读!如果你有任何问题或建议,欢迎在评论区留言。让我们一起在算法的世界中不断学习和进步!

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端每日三省

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值