{x}
blog image

Longest Common Subsequence

Given two strings text1 and text2, return the length of their longest common subsequence. If there is no common subsequence, return 0.

A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters.

  • For example, "ace" is a subsequence of "abcde".

A common subsequence of two strings is a subsequence that is common to both strings.

 

Example 1:

Input: text1 = "abcde", text2 = "ace" 
Output: 3  
Explanation: The longest common subsequence is "ace" and its length is 3.

Example 2:

Input: text1 = "abc", text2 = "abc"
Output: 3
Explanation: The longest common subsequence is "abc" and its length is 3.

Example 3:

Input: text1 = "abc", text2 = "def"
Output: 0
Explanation: There is no such common subsequence, so the result is 0.

 

Constraints:

  • 1 <= text1.length, text2.length <= 1000
  • text1 and text2 consist of only lowercase English characters.

Solution Explanation: Longest Common Subsequence

This problem asks for the length of the longest common subsequence (LCS) between two strings, text1 and text2. A subsequence is a sequence that can be derived from another sequence by deleting some or no elements without changing the order of the remaining elements. The solution utilizes dynamic programming for an efficient approach.

Approach: Dynamic Programming

The core idea is to build a 2D array (or matrix) f where f[i][j] represents the length of the LCS of the first i characters of text1 and the first j characters of text2.

  1. Initialization: The first row and column of f are initialized to 0 because an empty string has an LCS length of 0 with any other string.

  2. Iteration: The algorithm iterates through the remaining cells of the f matrix. For each cell f[i][j]:

    • If text1[i-1] (the i-th character of text1) equals text2[j-1] (the j-th character of text2), it means we've found a common character. In this case, the LCS length increases by 1, so f[i][j] = f[i-1][j-1] + 1.

    • Otherwise, if the characters are different, the LCS length is the maximum of the LCS lengths obtained by either excluding the i-th character from text1 (f[i-1][j]) or excluding the j-th character from text2 (f[i][j-1]). Therefore, f[i][j] = max(f[i-1][j], f[i][j-1]).

  3. Result: After iterating through the entire matrix, f[m][n] (where m and n are the lengths of text1 and text2 respectively) contains the length of the LCS of the entire strings.

Time and Space Complexity Analysis

  • Time Complexity: The algorithm iterates through the entire f matrix, which has dimensions (m+1) x (n+1). Therefore, the time complexity is O(mn), where 'm' and 'n' are the lengths of the input strings.

  • Space Complexity: The algorithm uses a 2D array f of size (m+1) x (n+1) to store the results. Therefore, the space complexity is also O(mn). Note that this could be optimized to O(min(m, n)) using space optimization techniques which only keep track of the previous row or column of the DP matrix.

Code Examples (with explanations)

The provided code examples in various programming languages all follow the same dynamic programming approach. Let's break down the Python3 example for clarity:

class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        m, n = len(text1), len(text2)
        f = [[0] * (n + 1) for _ in range(m + 1)] # Initialize the DP matrix with 0s
 
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if text1[i - 1] == text2[j - 1]: # Compare characters
                    f[i][j] = f[i - 1][j - 1] + 1  # Common character, increase LCS length
                else:
                    f[i][j] = max(f[i - 1][j], f[i][j - 1]) # Take the max from excluding one character
 
        return f[m][n] # The bottom-right cell contains the final LCS length

The other language examples are structurally similar, differing only in syntax and specific library functions (e.g., Math.max in Java/JavaScript vs max in Python/C++). They all implement the same dynamic programming algorithm to efficiently solve the longest common subsequence problem.