每日LeetCode —— 72. 编辑距离

74 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情

题目描述

给定两个单词word1、word2,长度分别为m、n。返回将word1转换为word2所需要的最小操作次数。可以使用的操作有:删除当前字符、替换当前字符、在当前字符后插入一个字符

例1:输入:"word1:"abcdaaa"   word2:"aabcaaa""  输出:"2"

解释:将输入的word1变为word2的操作方法有很多,比如在第一个word1[0]后分别插入abc,word1变为"aabcbcdaaa",然后删除word1的4、5、6位置的字符即可,这样操作的次数即为6次。此外,也可在word[0]后插入a,word1变为"aabcdaaa",然后将位置5的d删除,即可达到word2,这样操作的次数为2。在所有的变换方法中最少的操作次数即为2。

本题值得注意的地方

  • word1、word2均由小写字母组成。
  • word1与word2的长度m、n不一定是相同的。

原题地址:72. 编辑距离

解题思路

       当我们对word1的某一个字符进行变换操作时,可以选择的操作其实有四种:增加、删除、替换、不做任何操作。word2可以由word1做无数种种操作得到。

       这里定义 dp[i][j] 表示由 word1 的前 i 个字符得到 word2 的前 j 个字符所需要的最小操作数。则总结起来dp[i][j]可以由以下几种情形得到:

  1. 由dp[i-1][j]得到,dp[i-1][j]word1 的前 i-1 个字符得到 word2 的前 j 个字符所需要的最小操作数。即删除 word1[i]位置的字符。该情形可以得到状态转移方程为:dp[i][j]=dp[i1][j]+1dp[i][j] = dp[i-1][j] + 1
  2. 由dp[i][j-1],即在word1 的位置 i 后插入 字符word2[j]。该情形可以得到状态转移方程为:dp[i][j]=dp[i][j1]+1dp[i][j] = dp[i][j - 1] + 1
  3. 由dp[i-1][j-1],即将word1 i 位置的字符替换为 word2 j 位置的字符。但当word1[i]和word[j]相同时,就不必替换了。该情形可以得到状态转移方程为:dp[i][j]=word1[i]==word2[j]dp[i1][j1]dp[i1][j1]+1dp[i][j] = word1[i]==word2[j]?dp[i-1][j - 1]:dp[i-1][j - 1] + 1

       我们所求的答案就是dp[m][n]。

实现代码

class Solution {
public:
    int minDistance(string word1, string word2) {
        // 用来存储各种变化策略所需要的最小操作数
        vector<vector<int>> dp(word1.size()+1,vector<int>(word2.size()+1,0x3f3f3f3f));
        // 初始化用word1 的前0个字符得到word2的前i个字符,其所需最小操作就是添加字符的次数i次
        for(int i = 1;i <= word2.size();i++) dp[0][i] = i;
        // 初始化用word1 的前i个字符得到word2的前0个字符,其所需最小操作就是删除字符的次数i次
        for(int i = 1;i <= word1.size();i++) dp[i][0] = i;
        // "" -> "" 需要零次操作
        dp[0][0] = 0;
        // 依次计算从word1的前1、2、3·····m个字符得到word2的前1、2、3······n个字符所需要的操作次数
        for(int i = 1;i <= word1.size();i++){
            for(int j = 1;j <= word2.size();j++){
                // 计算word1的前i个字符转换为word2前j个字符所需要的最小操作次数
                dp[i][j] = min(dp[i-1][j],dp[i][j-1])+1;
                if(word1[i-1] == word2[j-1]) dp[i][j] = min(dp[i][j],dp[i-1][j-1]);
                else dp[i][j] = min(dp[i][j],dp[i-1][j-1]+1);
            }
        }
        // 返回word1 -> word2 的最小操作次数
        return dp[word1.size()][word2.size()];
    }
};