力扣算法题—072编辑距离

给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

  1. 插入一个字符
  2. 删除一个字符
  3. 替换一个字符

示例 1:

输入: word1 = "horse", word2 = "ros"
输出: 3
解释:
horse -> rorse (将 ‘h‘ 替换为 ‘r‘)
rorse -> rose (删除 ‘r‘)
rose -> ros (删除 ‘e‘)

示例 2:

输入: word1 = "intention", word2 = "execution"
输出: 5
解释:
intention -> inention (删除 ‘t‘)
inention -> enention (将 ‘i‘ 替换为 ‘e‘)
enention -> exention (将 ‘n‘ 替换为 ‘x‘)
exention -> exection (将 ‘n‘ 替换为 ‘c‘)
exection -> execution (插入 ‘u‘)
 1 #include "_000库函数.h"
 2
 3
 4 //不知道从何下手
 5 //参考博客答案
 6
 7 //要尝试三种操作,因为谁也不知道当前的操作会对后面产生什么样的影响,
 8 //那么对于当前比较的两个字符 word1[i] 和 word2[j],若二者相同,一切好说,
 9 //直接跳到下一个位置。若不相同,有三种处理方法,首先是直接插入一个 word2[j],那么 word2[j]
10 //位置的字符就跳过了,接着比较 word1[i] 和 word2[j + 1] 即可。
11 //第二个种方法是删除,即将 word1[i] 字符直接删掉,接着比较 word1[i + 1] 和 word2[j] 即可。
12 //第三种则是将 word1[i] 修改为 word2[j],接着比较 word1[i + 1] 和 word[j + 1] 即可。
13 //分析到这里,我们可以直接写出递归的代码,但是很可惜会 Time Limited Exceed,
14 //所以我们必须要优化事件复杂度,需要去掉大量的重复计算,
15 //这里我们使用记忆数组 memo 来保存计算过的状态,从而可以通过OJ,
16 //注意这里的 insertCnt,deleteCnt,replaceCnt 仅仅是表示当前对应的位置分别采用了插入,删除,和替换操作,
17 //整体返回的最小距离,后面位置的还是会调用递归返回最小的,参见代码如下:
18 class Solution {
19 public:
20     int minDistance(string word1, string word2) {
21         int m = word1.size(), n = word2.size();
22         vector<vector<int>> memo(m, vector<int>(n));
23         return helper(word1, 0, word2, 0, memo);
24     }
25     int helper(string& word1, int i, string& word2, int j, vector<vector<int>>& memo) {
26         if (i == word1.size()) return (int)word2.size() - j;
27         if (j == word2.size()) return (int)word1.size() - i;
28         if (memo[i][j] > 0) return memo[i][j];
29         int res = 0;
30         if (word1[i] == word2[j]) {
31             return helper(word1, i + 1, word2, j + 1, memo);
32         }
33         else {
34             int insertCnt = helper(word1, i, word2, j + 1, memo);
35             int deleteCnt = helper(word1, i + 1, word2, j, memo);
36             int replaceCnt = helper(word1, i + 1, word2, j + 1, memo);
37             res = min(insertCnt, min(deleteCnt, replaceCnt)) + 1;
38         }
39         return memo[i][j] = res;
40     }
41 };
42
43 //根据以往的经验,对于字符串相关的题目且求极值的问题,
44 //十有八九都是用动态规划Dynamic Programming来解,这道题也不例外。
45 //其实解法一的递归加记忆数组的方法也可以看作是DP的递归写法。
46 //这里我们需要维护一个二维的数组dp,其大小为 mxn,m和n分别为 word1 和word2 的长度。
47 //dp[i][j] 表示从 word1 的前i个字符转换到 word2 的前j个字符所需要的步骤。那
48 //我们可以先给这个二维数组dp的第一行第一列赋值,这个很简单,因为第一行和第一列对应的总有一个字符串是空串,
49 //于是转换步骤完全是另一个字符串的长度。跟以往的DP题目类似,难点还是在于找出状态转移方程,
50 //我们可以举个例子来看,比如word1是“bbc",word2是”abcd“,那么我们可以得到dp数组如下:
51
52
53 //Ø a b c d
54 //Ø 0 1 2 3 4
55 //b 1 1 1 2 3
56 //b 2 2 1 2 3
57 //c 3 3 2 1 2
58 //
59 //
60 //我们通过观察可以发现,当word1[i] == word2[j]时,dp[i][j] = dp[i - 1][j - 1],
61 //其他情况时,dp[i][j]是其左,左上,上的三个值中的最小值加1,其实这里的左,上,和左上,
62 //分别对应的增加,删除,修改操作,具体可以参见解法一种的讲解部分,那么可以得到状态转移方程为:
63 //
64 //if word1[i - 1] == word2[j - 1]
65 //    dp[i][j] = dp[i - 1][j - 1]
66 //else
67 //    min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1
68 //
69 //
70 class Solution {
71 public:
72     int minDistance(string word1, string word2) {
73         int m = word1.size(), n = word2.size();
74         vector<vector<int>> dp(m + 1, vector<int>(n + 1));
75         for (int i = 0; i <= m; ++i) dp[i][0] = i;
76         for (int i = 0; i <= n; ++i) dp[0][i] = i;
77         for (int i = 1; i <= m; ++i) {
78             for (int j = 1; j <= n; ++j) {
79                 if (word1[i - 1] == word2[j - 1]) {
80                     dp[i][j] = dp[i - 1][j - 1];
81                 }
82                 else {
83                     dp[i][j] = min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1;
84                 }
85             }
86         }
87         return dp[m][n];
88     }
89 };

原文地址:https://www.cnblogs.com/zzw1024/p/10705319.html

时间: 2024-11-05 17:17:37

力扣算法题—072编辑距离的相关文章

力扣算法题—042接雨水

1 #include"000库函数.h" 2 //一点头绪都没有 3 //然后就自己按自己的意思来一遍 4 //好像没有用算法 5 //16ms,让我激动一把 6 7 class Solution { 8 public: 9 int trap(vector<int>& height) { 10 if (height.size() < 2)return 0; 11 int s = 0;//起始点 12 int e = 0;//终止点 13 int v = 0;/

力扣算法题—050计算pow(x, n)

1 #include "000库函数.h" 2 3 4 5 //使用折半算法 牛逼算法 6 class Solution { 7 public: 8 double myPow(double x, int n) { 9 if (n == 0)return 1; 10 double res = 1.0; 11 for (int i = n; i != 0; i /= 2) { 12 if (i % 2 != 0) 13 res *= x; 14 x *= x; 15 } 16 return

力扣算法题—064最小路径之和

给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小. 说明:每次只能向下或者向右移动一步. 示例: 输入: [   [1,3,1], [1,5,1], [4,2,1] ] 输出: 7 解释: 因为路径 1→3→1→1→1 的总和最小. 1 #include "_000库函数.h" 2 3 //使用Dijkstra算法 4 //即动态规划 5 class Solution { 6 public: 7 int minPathSum(vec

力扣算法题—147Insertion_Sort_List

Sort a linked list using insertion sort. A graphical example of insertion sort. The partial sorted list (black) initially contains only the first element in the list.With each iteration one element (red) is removed from the input data and inserted in

力扣算法题—048旋转图像

1 #include "000库函数.h" 2 3 //找位置规律 4 //先不按照规则,使用另一个矩阵 5 class Solution { 6 public: 7 void rotate(vector<vector<int>>& matrix) { 8 vector < vector<int>>v = matrix; 9 int n = matrix.size(); 10 for (int t = 0; t < 1; +

力扣算法题—062不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” ). 机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角(在下图中标记为“Finish”). 问总共有多少条不同的路径? 例如,上图是一个7 x 3 的网格.有多少可能的路径? 说明:m 和 n 的值均不超过 100. 示例 1: 输入: m = 3, n = 2 输出: 3 解释: 从左上角开始,总共有 3 条路径可以到达右下角. 1. 向右 -> 向右 -> 向下 2. 向右 -> 向下

力扣算法题—078集合

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: nums = [1,2,3] 输出: [ [3],   [1],   [2],   [1,2,3],   [1,3],   [2,3],   [1,2],   [] ] 1 #include "_000库函数.h" 2 3 4 //这道题就是求不同的子集问题 5 class solution { 6 public: 7 vector<vector<i

力扣算法题—085最大矩阵

给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积. 示例: 输入: [ ["1","0","1","0","0"], ["1","0","1","1","1"], ["1","1","1","1&quo

力扣算法题—092反转链表2

反转从位置 m 到 n 的链表.请使用一趟扫描完成反转. 说明:1 ≤ m ≤ n ≤ 链表长度. 示例: 输入: 1->2->3->4->5->NULL, m = 2, n = 4 输出: 1->4->3->2->5->NULL 1 #include "_000库函数.h" 2 3 4 struct ListNode { 5 int val; 6 ListNode *next; 7 ListNode(int x) : val