By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
"This single problem type appears in 1 out of every 3 FAANG onsite interviews—master it, and you’ll prove you can break down complex string/DP problems with surgical precision."
Before tackling LCS, ensure you understand: 1. Dynamic Programming (DP) Basics – Memoization, tabulation, and state transitions. 2. String Manipulation – Substrings, subsequences, and character comparisons. 3. Recursion & Backtracking – How to decompose problems into smaller subproblems.
dp[i][j] = dp[i-1][j-1] + 1
s1[i-1] == s2[j-1]
max(dp[i-1][j], dp[i][j-1])
memo[i][j] = lcs(s1, s2, i-1, j-1) + 1
dp[m][n]
Ask: "Can we assume ASCII or Unicode strings?" (Affects space complexity.)
Define the DP State
dp[i][j] = LCS of s1[0..i-1] and s2[0..j-1]
Base Case: dp[0][j] = 0 (empty string), dp[i][0] = 0 (empty string).
dp[0][j] = 0
dp[i][0] = 0
Write the Recurrence Relation
Else → dp[i][j] = max(dp[i-1][j], dp[i][j-1])
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
Choose DP Approach
Memoization (Top-Down): Recursive with caching (easier to explain but slower).
Optimize Space (If Needed)
Use two 1D arrays (prev and curr) instead of a full 2D table.
prev
curr
Reconstruct the LCS (If Required)
Start from dp[m][n] and backtrack to build the subsequence.
Edge Cases & Testing
Test with s1 = "abc", s2 = "def" (LCS = "").
s1 = "abc"
s2 = "def"
""
Time & Space Complexity
Problem: Find the length of the LCS of "abcde" and "ace".
"abcde"
"ace"
Step-by-Step: 1. Initialize dp[m+1][n+1] (6x4 table, filled with 0s). 2. Fill the table: - dp[1][1] = 1 (a == a) - dp[2][2] = 1 (b != c) - dp[3][3] = 2 (c == c) - dp[5][3] = 3 (e == e) 3. Result: dp[5][3] = 3 (LCS = "ace").
dp[m+1][n+1]
dp[1][1] = 1
dp[2][2] = 1
dp[3][3] = 2
dp[5][3] = 3
Python Code:
def longestCommonSubsequence(s1: str, s2: str) -> int: m, n = len(s1), len(s2) dp = [[0] (n + 1) for _ in range(m + 1)] for i in range(1, m + 1): for j in range(1, n + 1): if s1[i-1] == s2[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]
Complexity: - Time: O(mn) - Space: O(mn) → Can be optimized to O(n).
Why This Works: - The DP table tracks the LCS length for all prefixes of s1 and s2. - The recurrence relation ensures we either extend the LCS (if characters match) or take the best of the two previous states.
s1
s2
Problem: Find the LCS length with O(n) space.
Approach: - Use two 1D arrays (prev and curr) instead of a full 2D table.
def longestCommonSubsequence(s1: str, s2: str) -> int: m, n = len(s1), len(s2) prev = [0] (n + 1) for i in range(1, m + 1): curr = [0] (n + 1) for j in range(1, n + 1): if s1[i-1] == s2[j-1]: curr[j] = prev[j-1] + 1 else: curr[j] = max(prev[j], curr[j-1]) prev = curr return prev[n]
Complexity: - Time: O(mn) - Space: O(n)
Why This Works: - We only need the previous row to compute the current row, reducing space.
Problem: Return the actual LCS string, not just its length.
Approach: 1. Compute the DP table as before. 2. Backtrack from dp[m][n] to build the LCS.
def longestCommonSubsequence(s1: str, s2: str) -> str: m, n = len(s1), len(s2) dp = [[0] (n + 1) for _ in range(m + 1)] for i in range(1, m + 1): for j in range(1, n + 1): if s1[i-1] == s2[j-1]: dp[i][j] = dp[i-1][j-1] + 1 else: dp[i][j] = max(dp[i-1][j], dp[i][j-1]) # Backtrack to reconstruct LCS i, j = m, n lcs = [] while i > 0 and j > 0: if s1[i-1] == s2[j-1]: lcs.append(s1[i-1]) i -= 1 j -= 1 elif dp[i-1][j] > dp[i][j-1]: i -= 1 else: j -= 1 return ''.join(reversed(lcs))
Complexity: - Time: O(mn) - Space: O(mn)
Why This Works: - The backtracking step follows the DP table to reconstruct the LCS by moving diagonally when characters match.
s1[i]
s1[i-1]
dp[i][j]
s1[0..i-1]
s2[0..j-1]
min
max
"Alright, let’s lock this in. The Longest Common Subsequence problem is a DP classic—you’ll see it in Google, Meta, and Amazon interviews because it tests your ability to break down string problems with precision.
Here’s your 30-second cheat sheet: 1. Define dp[i][j] as the LCS of s1[0..i-1] and s2[0..j-1]. 2. Fill the table with dp[i][j] = dp[i-1][j-1] + 1 if characters match, else max(dp[i-1][j], dp[i][j-1]). 3. Optimize space with two 1D arrays if needed. 4. Reconstruct the LCS by backtracking from dp[m][n].
Edge cases? Empty strings, identical strings, no common subsequence. Time complexity? O(mn). Space? O(mn) → O(n) with optimization.
Now go crush that interview. You’ve got this!
Good luck! ?
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.