Intuition
Define dp[i][j] = the minimum edits to transform word1[:i] into word2[:j] (the first i characters of word1 into the first j of word2). Two cases at each cell: the last characters match (free, copy from the diagonal), or they don't (we paid one op for either insert / delete / replace, take whichever is cheapest).
Explanation
The recurrence
For i, j ≥ 1:
- If
word1[i-1] == word2[j-1]:dp[i][j] = dp[i-1][j-1]— no operation needed at this position; whatever we did to align the prefixes carries over. - Otherwise:
dp[i][j] = 1 + min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]). The three cases correspond to:dp[i-1][j-1] + 1— replaceword1[i-1]withword2[j-1].dp[i-1][j] + 1— deleteword1[i-1].dp[i][j-1] + 1— insertword2[j-1].
Base cases: dp[0][j] = j (insert j chars to build word2[:j] from empty) and dp[i][0] = i (delete all i chars to reduce word1[:i] to empty).
Steps
- Allocate
dpof size(m+1) × (n+1). - Fill the first row and first column with
0..nand0..mrespectively. - For each
ifrom1tom, for eachjfrom1ton, filldp[i][j]using the recurrence. - Return
dp[m][n].
Walk-through
word1 = "horse", word2 = "ros". Expected answer: 3.
| dp | "" | r | o | s |
|---|---|---|---|---|
| "" | 0 | 1 | 2 | 3 |
| h | 1 | 1 | 2 | 3 |
| ho | 2 | 2 | 1 | 2 |
| hor | 3 | 2 | 2 | 2 |
| hors | 4 | 3 | 3 | 2 |
| horse | 5 | 4 | 4 | 3 |
Walking the bottom-right back: from dp[5][3] = 3, the path could be:
- Replace
h→r(1 op). - Skip the
o(match). - Delete
r, deletes, thene→ wait, let's read the table more carefully. The standard path:horse → rorse (replace h→r) → rose (delete r) → ros (delete e). Three ops. ✓
Why three options always cover the case
Any single edit step transforms the source into something where the last char either isn't there (delete), is new (insert), or swapped (replace). After one such step, the remaining problem is a smaller dp cell — exactly the three transitions above.
Edge cases
- One word is empty: answer is the length of the other.
- Identical strings: zero ops; the diagonal stays at
0.
Complexity
- Time:
O(m · n)— one pass to fill the table. - Space:
O(m · n)— the full table.
Implementation
class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length(), n = word2.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++) {
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = 1 + Math.min(dp[i - 1][j - 1],
Math.min(dp[i - 1][j], dp[i][j - 1]));
}
}
}
return dp[m][n];
}
}