返回

力扣题目剖析:程序员必刷之最长公共子序列

前端

前言

在程序员的成长道路上,力扣是一座无法逾越的高峰。它汇集了大量经典算法和数据结构题目,是检验程序员基本功的试金石。其中,「最长公共子序列」更是必刷题目之一。这道题不仅考察了你的算法能力,还考验了你的字符串处理技巧。

题目

给你两个字符串text1text2,请你找出这两个字符串的最长公共子序列。一个字符串的子序列是指从该字符串中删除任意数量字符(也可以不删除)后剩余的字符串。例如,字符串 "abc" 的子序列包括 "a""b""c""ab""ac""bc""abc"

解题思路

求最长公共子序列可以使用动态规划算法。我们定义一个二维数组dp,其中dp[i][j]表示text1的前i个字符和text2的前j个字符的最长公共子序列长度。

动态规划算法的递推公式如下:

dp[i][j] = dp[i - 1][j - 1] + 1,如果 text1[i] == text2[j]
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]),如果 text1[i] != text2[j]

代码实现

Python:

def longest_common_subsequence(text1, text2):
  m, n = len(text1), len(text2)
  dp = [[0] * (n + 1) for _ in range(m + 1)]

  for i in range(1, m + 1):
    for j in range(1, n + 1):
      if text1[i - 1] == text2[j - 1]:
        dp[i][j] = dp[i - 1][j - 1] + 1
      else:
        dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

  return dp[m][n]

Java:

public int longestCommonSubsequence(String text1, String text2) {
  int m = text1.length(), n = text2.length();
  int[][] dp = new int[m + 1][n + 1];

  for (int i = 1; i <= m; i++) {
    for (int j = 1; j <= n; j++) {
      if (text1.charAt(i - 1) == text2.charAt(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];
}

C++:

int longestCommonSubsequence(string text1, string text2) {
  int m = text1.size(), n = text2.size();
  vector<vector<int>> dp(m + 1, vector<int>(n + 1));

  for (int i = 1; i <= m; i++) {
    for (int 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] = max(dp[i - 1][j], dp[i][j - 1]);
      }
    }
  }

  return dp[m][n];
}

复杂度分析

时间复杂度:O(mn),其中m和n分别为text1text2的长度。

空间复杂度:O(mn),其中m和n分别为text1text2的长度。

结语

「最长公共子序列」是力扣题库中一道经典题目,掌握它将极大地提升你的算法和字符串处理能力。通过本文的详细解析和代码示例,相信你已经对这道题有了深刻的理解。在今后的编程生涯中,希望这篇文章能成为你解决类似问题的指南。

延伸阅读