LeetCode 72. 编辑距离

描述

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

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

插入一个字符
删除一个字符
替换一个字符

示例 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’)

提示:
0 <= word1.length, word2.length <= 500
word1 和 word2 由小写英文字母组成

思路

这是动态规划中难度比较大的题了。从word1变到word2和word2变到word1是一样的(后者是前者的逆过程)。dp数组的定义都比较难想到,状态转移方程就更不必说了。既然要从word1变到word2,参考前面的最长公共子序列问题,用动态规划的思想来考虑,肯定是从word1的前0个字符开始,一直考虑到前n个字符(m为word1总长度),对照着word2中的前0个字符到前n个字符(n为word2的总长度),利用状态转移方程,每一次遍历都进行最优选择。

那么,dp数组的含义差不多就能想到了:dp[i][j]就代表word1的前i个字符转换到word的前j个字符所需要的最小编辑距离。

初始值:因为从word1的前0个字符->word2的前j个字符 需要j步,所以dp[0][j] = j;同理,从word1的前i个字符->word2的前0个字符 需要i步,dp[i][0] = i

状态转移方程:

dp[i][j]取决于什么呢?(1)当word1[i - 1]word2[j - 1](字符串索引从0开始,所以是i - 1和j - 1)相等时,那么就不需要进行任何操作,什么也不做一定是当前的最优解,因为其他3种操作都会增加编辑距离。dp[i][j] = dp[i - 1][j - 1],即继承前i -1、j - 1个字符的最小编辑距离。(2)如果word1[i - 1]word2[j - 1]不相等,那么就需要考虑题设的三种操作了:插入、删除、替换。应该进行哪种操作取决于谁呢?

  • 删除:如果从word1的前i-1个字符变到word2的前j个字符需要k步,那么从word1的前i个字符变到word2的前j个字符只需要将word1[i - 1]删除即可。即dp[i][j] = dp[i - 1][j] + 1
  • 插入:如果从word1的前i个字符变到word2的前j-1个字符需要k步,那么从word1的前i个字符变到word2的前j个字符只需要在word1后面插入word[j - 1]的值即可。即dp[i][j] = dp[i ][j - 1] + 1
  • 替换:如果从word1的前i - 1个字符到word2的前j -1个字符需要k步,那么从word1的前i个字符变到word2的前j个字符只需要将word[i - 1]替换为word[j - 1]即可。即dp[i][j] = dp[i - 1][j - 1] + 1

这样状态转移方程就列完了,每次都在四种操作(第一种什么也不做也算一种操作)中抉择即可。

参考:来自LeetCode下的精选评论
在这插入图片描述

解答

class Solution {
public:
    int minDistance(string word1, string word2) {
        int len1 = word1.length();
        int len2 = word2.length();
        //dp数组,定义为:word1的前i个字符->word2的前j个字符 最少需要多少步
        vector<vector<int> > dp(len1 + 1, vector(len2 + 1, 0));
        
        //初始值:
        //因为从word1的前0个字符->word2的前j个字符 需要j步,所以dp[0][j] = j
        //同理,从word1的前i个字符->word2的前0个字符 需要i步,dp[i][0] = i
        for(int i = 1;i <= len1; ++ i) dp[i][0] = i;
        for(int j = 1;j <= len2; ++ j) dp[0][j] = j;

        //状态转移方程
        for(int i = 1;i <= len1; ++ i)
            for(int j = 1;j <= len2; ++ j)
                    if(word1[i - 1] == word2[j - 1])
                        dp[i][j] = dp[i - 1][j - 1];
                    else dp[i][j] = min(dp[i - 1][j], 
                            min(dp[i][j - 1], dp[i - 1][j - 1])) + 1;
    return dp[len1][len2];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值