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.
"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 <= 1000text1 and text2 consist of only lowercase English characters.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
To find the longest shared sequence of letters between two words, the brute force strategy is to look at every possible sequence of letters from the first word. Then, for each of those sequences, we check if it can also be found in the second word, in the same order.
Here's how the algorithm would work step-by-step:
def longest_common_subsequence_brute_force(text1, text2):
longest_length_so_far = 0
def generate_all_subsequences(index, current_subsequence, all_subsequences):
if index == len(text1):
if current_subsequence:
all_subsequences.add(current_subsequence)
return
# This recursive call generates subsequences that include the character at the current index.
generate_all_subsequences(index + 1, current_subsequence + text1[index], all_subsequences)
# This recursive call generates subsequences that do NOT include the character at the current index.
generate_all_subsequences(index + 1, current_subsequence, all_subsequences)
all_subsequences_of_text1 = set()
generate_all_subsequences(0, "", all_subsequences_of_text1)
for candidate_subsequence in all_subsequences_of_text1:
text2_pointer = 0
subsequence_pointer = 0
while text2_pointer < len(text2) and subsequence_pointer < len(candidate_subsequence):
if text2[text2_pointer] == candidate_subsequence[subsequence_pointer]:
subsequence_pointer += 1
text2_pointer += 1
# We must check if the entire candidate subsequence was found within text2.
if subsequence_pointer == len(candidate_subsequence):
if len(candidate_subsequence) > longest_length_so_far:
longest_length_so_far = len(candidate_subsequence)
return longest_length_so_farInstead of checking every possible combination of shared parts, we can build a solution by making a series of smaller, simpler decisions. We'll create a table to keep track of the best answers for smaller pieces of the original problem and use those results to figure out the final answer.
Here's how the algorithm would work step-by-step:
def longest_common_subsequence(text1, text2):
length_of_text1 = len(text1)
length_of_text2 = len(text2)
# This grid stores the LCS length for all subproblems.
dp_grid = [[0] * (length_of_text2 + 1) for _ in range(length_of_text1 + 1)]
for row_index in range(1, length_of_text1 + 1):
for column_index in range(1, length_of_text2 + 1):
# If characters match, the LCS is one longer than the LCS of the preceding substrings.
if text1[row_index - 1] == text2[column_index - 1]:
dp_grid[row_index][column_index] = 1 + dp_grid[row_index - 1][column_index - 1]
else:
# If they don't match, we must take the best result from the subproblems.
dp_grid[row_index][column_index] = max(dp_grid[row_index - 1][column_index], dp_grid[row_index][column_index - 1])
# The bottom-right cell contains the solution for the full strings.
return dp_grid[length_of_text1][length_of_text2]| Case | How to Handle |
|---|---|
| One or both input strings are empty | The longest common subsequence with an empty string is always of length 0, which the base cases of the dynamic programming solution correctly establish. |
| Input strings are identical | The algorithm will correctly return the length of the string itself, as the entire string is its own longest common subsequence. |
| Input strings have no characters in common | The algorithm will correctly return 0 as no matches will be found during the comparison process. |
| One string is a subsequence of the other | The solution correctly identifies the shorter string as the longest common subsequence and returns its length. |
| Strings with a single character | The solution will correctly return 1 if the characters are the same and 0 otherwise. |
| Strings containing special characters, numbers, or different cases | The character comparisons are based on their underlying values, so the algorithm handles any valid character set correctly. |
| Very long input strings (e.g., up to 1000 characters each) | A dynamic programming approach with O(m*n) time and space complexity is efficient enough to pass within typical time limits for these constraints. |
| Strings with highly repetitive characters (e.g., 'aaaaa' and 'aa') | The dynamic programming solution correctly handles repeated characters by considering their positions and relative order. |