Welcome to Subscribe On Youtube
72. Edit Distance
Description
Given two strings word1 and word2, return the minimum number of operations required to convert word1 to word2.
You have the following three operations permitted on a word:
- Insert a character
- Delete a character
- Replace a character
Example 1:
Input: word1 = "horse", word2 = "ros" Output: 3 Explanation: horse -> rorse (replace 'h' with 'r') rorse -> rose (remove 'r') rose -> ros (remove 'e')
Example 2:
Input: word1 = "intention", word2 = "execution" Output: 5 Explanation: intention -> inention (remove 't') inention -> enention (replace 'i' with 'e') enention -> exention (replace 'n' with 'x') exention -> exection (replace 'n' with 'c') exection -> execution (insert 'u')
Constraints:
0 <= word1.length, word2.length <= 500word1andword2consist of lowercase English letters.
Solutions
Solution 1: Dynamic Programming
We define $f[i][j]$ as the minimum number of operations to convert $word1$ of length $i$ to $word2$ of length $j$. $f[i][0] = i$, $f[0][j] = j$, $i \in [1, m], j \in [0, n]$.
We consider $f[i][j]$:
- If $word1[i - 1] = word2[j - 1]$, then we only need to consider the minimum number of operations to convert $word1$ of length $i - 1$ to $word2$ of length $j - 1$, so $f[i][j] = f[i - 1][j - 1]$;
- Otherwise, we can consider insert, delete, and replace operations, then $f[i][j] = \min(f[i - 1][j], f[i][j - 1], f[i - 1][j - 1]) + 1$.
Finally, we can get the state transition equation:
\[f[i][j] = \begin{cases} i, & \text{if } j = 0 \\ j, & \text{if } i = 0 \\ f[i - 1][j - 1], & \text{if } word1[i - 1] = word2[j - 1] \\ \min(f[i - 1][j], f[i][j - 1], f[i - 1][j - 1]) + 1, & \text{otherwise} \end{cases}\]Finally, we return $f[m][n]$.
The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. $m$ and $n$ are the lengths of $word1$ and $word2$ respectively.
-
class Solution { public int minDistance(String word1, String word2) { int m = word1.length(), n = word2.length(); int[][] f = new int[m + 1][n + 1]; for (int j = 1; j <= n; ++j) { f[0][j] = j; } for (int i = 1; i <= m; ++i) { f[i][0] = i; for (int j = 1; j <= n; ++j) { if (word1.charAt(i - 1) == word2.charAt(j - 1)) { f[i][j] = f[i - 1][j - 1]; } else { f[i][j] = Math.min(f[i - 1][j], Math.min(f[i][j - 1], f[i - 1][j - 1])) + 1; } } } return f[m][n]; } } -
class Solution { public: int minDistance(string word1, string word2) { int m = word1.size(), n = word2.size(); int f[m + 1][n + 1]; for (int j = 0; j <= n; ++j) { f[0][j] = j; } for (int i = 1; i <= m; ++i) { f[i][0] = i; for (int j = 1; j <= n; ++j) { if (word1[i - 1] == word2[j - 1]) { f[i][j] = f[i - 1][j - 1]; } else { f[i][j] = min({f[i - 1][j], f[i][j - 1], f[i - 1][j - 1]}) + 1; } } } return f[m][n]; } }; -
class Solution: def minDistance(self, word1: str, word2: str) -> int: m, n = len(word1), len(word2) dp = [[0] * (n + 1) for _ in range(m + 1)] for i in range(m + 1): dp[i][0] = i for j in range(n + 1): dp[0][j] = j for i in range(1, m + 1): for j in range(1, n + 1): if word1[i - 1] == word2[j - 1]: dp[i][j] = dp[i - 1][j - 1] else: # dp[i - 1][j - 1]) meaning replace. # e.g. "abc" and "bf", checking "ab" and "b" distance, # then replace either way for "c" or "f" dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]) return dp[-1][-1] ############ class Solution: def minDistance(self, word1: str, word2: str) -> int: m, n = len(word1), len(word2) f = [[0] * (n + 1) for _ in range(m + 1)] for j in range(1, n + 1): f[0][j] = j for i, a in enumerate(word1, 1): f[i][0] = i # merged for loops from above solution, but not good for readability for j, b in enumerate(word2, 1): if a == b: f[i][j] = f[i - 1][j - 1] else: f[i][j] = min(f[i - 1][j], f[i][j - 1], f[i - 1][j - 1]) + 1 return f[m][n] -
func minDistance(word1 string, word2 string) int { m, n := len(word1), len(word2) f := make([][]int, m+1) for i := range f { f[i] = make([]int, n+1) } for j := 1; j <= n; j++ { f[0][j] = j } for i := 1; i <= m; i++ { f[i][0] = i for j := 1; j <= n; j++ { if word1[i-1] == word2[j-1] { f[i][j] = f[i-1][j-1] } else { f[i][j] = min(f[i-1][j], min(f[i][j-1], f[i-1][j-1])) + 1 } } } return f[m][n] } -
function minDistance(word1: string, word2: string): number { const m = word1.length; const n = word2.length; const f: number[][] = Array(m + 1) .fill(0) .map(() => Array(n + 1).fill(0)); for (let j = 1; j <= n; ++j) { f[0][j] = j; } for (let i = 1; i <= m; ++i) { f[i][0] = i; for (let j = 1; j <= n; ++j) { if (word1[i - 1] === word2[j - 1]) { f[i][j] = f[i - 1][j - 1]; } else { f[i][j] = Math.min(f[i - 1][j], f[i][j - 1], f[i - 1][j - 1]) + 1; } } } return f[m][n]; } -
/** * @param {string} word1 * @param {string} word2 * @return {number} */ var minDistance = function (word1, word2) { const m = word1.length; const n = word2.length; const f = Array(m + 1) .fill(0) .map(() => Array(n + 1).fill(0)); for (let j = 1; j <= n; ++j) { f[0][j] = j; } for (let i = 1; i <= m; ++i) { f[i][0] = i; for (let j = 1; j <= n; ++j) { if (word1[i - 1] === word2[j - 1]) { f[i][j] = f[i - 1][j - 1]; } else { f[i][j] = Math.min(f[i - 1][j], f[i][j - 1], f[i - 1][j - 1]) + 1; } } } return f[m][n]; };