Longest Common Subsequence in DSA C# - Time & Space Complexity
We want to understand how the time needed to find the longest common subsequence grows as the input strings get longer.
The question is: How does the running time change when the strings become bigger?
Analyze the time complexity of the following code snippet.
int LCS(string s1, string s2) {
int m = s1.Length, n = s2.Length;
int[,] dp = new int[m + 1, n + 1];
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (s1[i - 1] == s2[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];
}
This code finds the length of the longest common subsequence between two strings using a table to store results.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Nested loops over both strings to fill the dp table.
- How many times: The inner code runs once for each pair of characters, so m x n times.
As the strings get longer, the number of operations grows with the product of their lengths.
| Input Size (m, n) | Approx. Operations |
|---|---|
| 10, 10 | 100 |
| 100, 100 | 10,000 |
| 1000, 1000 | 1,000,000 |
Pattern observation: Doubling the length of both strings roughly quadruples the work.
Time Complexity: O(m x n)
This means the time needed grows proportionally to the product of the lengths of the two strings.
[X] Wrong: "The algorithm runs in linear time because it just compares characters."
[OK] Correct: It compares pairs of characters from both strings, so the work grows with both lengths multiplied, not just one.
Understanding this time complexity helps you explain how dynamic programming improves efficiency over simple recursion, a key skill in problem solving.
"What if we used recursion without memoization? How would the time complexity change?"
Practice
Solution
Step 1: Define subsequence
A subsequence maintains relative order of characters but does not require them to be contiguous. 'ace' is a subsequence of 'abcde'.Step 2: LCS definition
LCS is the longest such subsequence common to both strings. For 'ABCBDAB' and 'BDCAB', LCS is 'BCAB' or 'BDAB', length 4.Final Answer:
Longest common subsequence - same order, not necessarily contiguous. -> Option AQuick Check:
Subsequence = order preserved, not contiguous. LCS = longest shared one. [OK]
- Confusing subsequence with substring (substring must be contiguous)
- Thinking LCS is the shortest common supersequence
- Assuming characters must be adjacent
Solution
Step 1: Find common subsequences
Characters in both: A, C, D. Check order: A appears before C in both. C appears before D in both. So 'ACD' is a common subsequence of length 3.Step 2: Can we do better?
'ABCD' and 'ACDF' share A, C, D in order. B is not in Y. F is not in X. No common subsequence of length 4 exists.Final Answer:
LCS = "ACD", length 3. -> Option BQuick Check:
A→C→D in both strings: length 3. [OK]
- Counting all common characters without checking order
- Including B which is not in Y
- Stopping at 2 by missing D
Solution
Step 1: When characters match
If X[i] == Y[j], the current characters extend the LCS found without them. We add 1 to the LCS of X[0..i-1] and Y[0..j-1].Step 2: Recurrence
dp[i][j] = dp[i-1][j-1] + 1. We extend the diagonal neighbor by 1.Step 3: When they don't match
dp[i][j] = max(dp[i-1][j], dp[i][j-1]) - take the best from skipping either character.Final Answer:
dp[i-1][j-1] + 1 -> Option BQuick Check:
Match → diagonal + 1. No match → max of left and above. [OK]
- Using dp[i-1][j-1] without adding 1
- Using max formula when characters match
- Adding 1 to dp[i][j-1] instead of diagonal
Solution
Step 1: Time complexity
We fill a 2D table of size (m+1)×(n+1), computing each cell in O(1). Total: O(m×n).Step 2: Space complexity
The full 2D DP table requires O(m×n) space. Space can be optimized to O(min(m,n)) using two rows, but standard solution uses O(m×n).Final Answer:
Time O(m×n), Space O(m×n) -> Option BQuick Check:
Standard 2D table = O(m×n) both time and space. [OK]
- Saying O(m+n) which is linear - LCS needs quadratic
- Reporting space-optimized O(min(m,n)) for the standard solution
- Confusing with exponential recursion without memoization
Solution
Step 1: Identify LCS
X = 'AGGTAB', Y = 'GXTXAYB'. Common subsequences include 'GTAB' (length 4): G(1,0)→T(2,3)→A(4,4)→B(5,6).Step 2: Verify length 4
G: appears in both at valid positions. T: X[2]='G',X[2]='G'... Let's check: X='A,G,G,T,A,B'. Y='G,X,T,X,A,Y,B'. Common: G(X[1],Y[0]), T(X[3],Y[2]), A(X[4],Y[4]), B(X[5],Y[6]) → GTAB length 4.Final Answer:
dp[6][7] = 4 -> Option BQuick Check:
LCS of 'AGGTAB' and 'GXTXAYB' is 'GTAB' = length 4. [OK]
- Confusing LCS length with string length
- Incorrectly tracing the DP table
- Getting 3 by missing one character in the subsequence
Ready to prove it?
Pass the test and this pattern moves unknown
