Edit Distance Problem Levenshtein in DSA C# - Time & Space Complexity
We want to understand how the time needed to find the edit distance between two words grows as the words get longer.
How does the work increase when the input words become bigger?
Analyze the time complexity of the following code snippet.
public int LevenshteinDistance(string s, string t) {
int m = s.Length, n = t.Length;
int[,] dp = new int[m + 1, n + 1];
for (int i = 0; i <= m; i++) dp[i, 0] = i;
for (int j = 0; j <= n; j++) dp[0, j] = j;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
int cost = s[i - 1] == t[j - 1] ? 0 : 1;
dp[i, j] = Math.Min(Math.Min(dp[i - 1, j] + 1, dp[i, j - 1] + 1), dp[i - 1, j - 1] + cost);
}
}
return dp[m, n];
}
This code calculates the minimum number of edits needed to change one word into another using a grid of subproblems.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Nested loops filling a 2D table of size m by n.
- How many times: The inner loop runs n times for each of the m iterations of the outer loop, so roughly m x n times.
As the lengths of the two words increase, the number of operations grows by multiplying 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 words roughly quadruples the work needed.
Time Complexity: O(m * n)
This means the time needed grows proportionally to the product of the lengths of the two input words.
[X] Wrong: "The algorithm runs in linear time because it just loops through the words once."
[OK] Correct: The algorithm uses two nested loops, so it checks every pair of characters, making the work multiply, not just add.
Understanding this time complexity helps you explain how dynamic programming solves problems efficiently by breaking them into smaller parts.
"What if we used recursion without memoization? How would the time complexity change?"
Practice
Solution
Step 1: Understand the definition of Levenshtein distance
It counts the minimum edits (insertions, deletions, substitutions) to convert one string into another.Step 2: Compare with other options
Options B and C describe different string metrics, not edit distance.Final Answer:
The minimum number of single-character edits to change one string into another -> Option DQuick Check:
Edit distance = minimum edits [OK]
- Confusing edit distance with longest common substring
- Thinking it counts only substitutions
- Assuming it measures string length
s1 and s2?Solution
Step 1: Check parameter types for string inputs
The function should accept two strings, so parameters must be string types.Step 2: Check return type for distance value
Distance is an integer, so return type should be int, not void or string.Final Answer:
public int LevenshteinDistance(string s1, string s2) -> Option CQuick Check:
Function signature matches string inputs and int output [OK]
- Using void return type instead of int
- Using int parameters instead of strings
- Returning string instead of int
var s1 = "kitten";
var s2 = "sitting";
Console.WriteLine(LevenshteinDistance(s1, s2));
int LevenshteinDistance(string a, string b) {
int[,] dp = new int[a.Length + 1, b.Length + 1];
for (int i = 0; i <= a.Length; i++) dp[i, 0] = i;
for (int j = 0; j <= b.Length; j++) dp[0, j] = j;
for (int i = 1; i <= a.Length; i++) {
for (int j = 1; j <= b.Length; j++) {
int cost = (a[i - 1] == b[j - 1]) ? 0 : 1;
dp[i, j] = Math.Min(Math.Min(dp[i - 1, j] + 1, dp[i, j - 1] + 1), dp[i - 1, j - 1] + cost);
}
}
return dp[a.Length, b.Length];
}
Solution
Step 1: Understand the strings and operations
"kitten" to "sitting" requires substitutions, insertions, deletions.Step 2: Calculate Levenshtein distance manually
Changes: k->s (substitution), e->i (substitution), t->t (no change), t->t (no change), e->i (substitution), n->n (no change), add g (insertion) = 3 substitutions + 1 insertion = 4 edits total.Final Answer:
4 -> Option BQuick Check:
Distance("kitten", "sitting") = 4 [OK]
- Counting only substitutions, ignoring insertions
- Miscounting character positions
- Confusing with Hamming distance
int LevenshteinDistance(string a, string b) {
int[,] dp = new int[a.Length, b.Length];
for (int i = 0; i < a.Length; i++) dp[i, 0] = i;
for (int j = 0; j < b.Length; j++) dp[0, j] = j;
for (int i = 1; i < a.Length; i++) {
for (int j = 1; j < b.Length; j++) {
int cost = (a[i] == b[j]) ? 0 : 1;
dp[i, j] = Math.Min(Math.Min(dp[i - 1, j] + 1, dp[i, j - 1] + 1), dp[i - 1, j - 1] + cost);
}
}
return dp[a.Length - 1, b.Length - 1];
}Solution
Step 1: Check array size and indexing
dp array must be sized (a.Length+1, b.Length+1) to include empty prefixes; current size misses last row/column.Step 2: Adjust loops to run from 0 to length inclusive
Loops should run to <= length to fill dp correctly; current loops miss last indices.Final Answer:
Array size should be (a.Length+1, b.Length+1) and loops adjusted -> Option AQuick Check:
dp array size must include empty string row/column [OK]
- Using array size equal to string length only
- Incorrect loop bounds causing index errors
- Ignoring empty string base cases
s1 = "intention" and s2 = "execution", what is the Levenshtein distance between them? Use the standard operations: insert, delete, substitute.Solution
Step 1: Analyze differences between "intention" and "execution"
Compare characters and count minimal edits: substitutions and insertions/deletions.Step 2: Calculate minimal edits manually
Edits: i->e (substitution), n->x (substitution), t->c (substitution), insert u, substitute n->o, substitute n->n (no change), total 5 edits.Final Answer:
5 -> Option AQuick Check:
Distance("intention", "execution") = 5 [OK]
- Underestimating substitutions needed
- Ignoring insertions or deletions
- Confusing with Hamming distance
Ready to prove it?
Pass the test and this pattern moves unknown
