[LeetCode] 72. Edit Distance

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 -> ine ntion (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 <= 500
  • word1 and word2 consist of lowercase English letters.

编辑距离。

题意是给两个字符串 word1 和 word2,请返回将 word1 转换成 word2 所使用的最少操作数。这是动态规划的经典题。创建一个二维的数组 dp[i][j] ,代表 word1 到 i 位置转换成 word2 到 j 位置需要最少步数。要让两个单词相同,分三种情况,

  • word1减去一个字母 == word2加上一个字母(这两者是等价的所以是同一种情况)
  • word1加上一个字母 == word2减去一个字母(等价)
  • word1修改一个字母 == word2修改一个字母(等价)

所以判断 DP 下一步的值的时候需要判断当前字母是否相同,若相同则不需要做任何转换,DP 值来源于上一个位置的 DP 值,dp[i][j] = dp[i - 1][j - 1];若不相同则需要判断如下三种情况哪一种的开销小,

  • dp[i - 1][j] - A 的前 i - 1 个字符和 B 的前 j 个字符的子问题
  • dp[i][j - 1] - A 的前 i 个字符和 B 的前 j - 1 个字符的子问题
  • dp[i-1][j-1] - A 的前 i - 1 个字符和 B 的前 j  - 1 个字符的子问题

我在讨论区看到一个很好的评论帮助理解,贴在这里。

  • 对“dp[i-1][j-1] 表示替换操作,dp[i-1][j] 表示删除操作,dp[i][j-1] 表示插入操作。”的补充理解:
  • 以 word1 为 "horse",word2 为 "ros",且 dp[5][3] 为例,即要将 word1的前 5 个字符转换为 word2的前 3 个字符,也就是将 horse 转换为 ros,因此有:
  • (1) dp[i-1][j-1],即先将 word1 的前 4 个字符 hors 转换为 word2 的前 2 个字符 ro,然后将第五个字符 word1[4](因为下标基数以 0 开始) 由 e 替换为 s(即替换为 word2 的第三个字符,word2[2])
  • (2) dp[i][j-1],即先将 word1 的前 5 个字符 horse 转换为 word2 的前 2 个字符 ro,然后在末尾补充一个 s,即插入操作
  • (3) dp[i-1][j],即先将 word1 的前 4 个字符 hors 转换为 word2 的前 3 个字符 ros,然后删除 word1 的第 5 个字符

时间O(mn)

空间O(mn)

Java实现

 1 class Solution {
 2     public int minDistance(String word1, String word2) {
 3         int len1 = word1.length();
 4         int len2 = word2.length();
 5         int[][] dp = new int[len1 + 1][len2 + 1];
 6         for (int i = 0; i <= len1; i++) {
 7             dp[i][0] = i;
 8         }
 9         for (int j = 0; j <= len2; j++) {
10             dp[0][j] = j;
11         }
12         for (int i = 1; i <= len1; i++) {
13             for (int j = 1; j <= len2; j++) {
14                 if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
15                     dp[i][j] = dp[i - 1][j - 1];
16                 } else {
17                     dp[i][j] = 1 + Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]);
18                 }
19             }
20         }
21         return dp[len1][len2];
22     }
23 }

 

JavaScript实现

 1 /**
 2  * @param {string} word1
 3  * @param {string} word2
 4  * @return {number}
 5  */
 6 var minDistance = function(word1, word2) {
 7     let len1 = word1.length;
 8     let len2 = word2.length;
 9     let dp = Array(word1.length + 1)
10         .fill(null)
11         .map(() => Array(word2.length + 1).fill(0));
12     for (let i = 0; i <= len1; i++) {
13         dp[i][0] = i;
14     }
15     for (let j = 0; j <= len2; j++) {
16         dp[0][j] = j;
17     }
18     for (let i = 1; i <= len1; i++) {
19         for (let j = 1; j <= len2; j++) {
20             if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
21                 dp[i][j] = dp[i - 1][j - 1];
22             } else {
23                 dp[i][j] =
24                     1 +
25                     Math.min(
26                         Math.min(dp[i - 1][j], dp[i][j - 1]),
27                         dp[i - 1][j - 1]
28                     );
29             }
30         }
31     }
32     return dp[i][j];
33 };

 

相关题目

72. Edit Distance

583. Delete Operation for Two Strings

LeetCode 题目总结

posted @ 2020-04-07 00:49  CNoodle  阅读(475)  评论(0编辑  收藏  举报