72. 编辑距离

在这里插入图片描述
在这里插入图片描述
光看题目是不可能做的出这道题的,两个字符串的最优解问题,一定要想到二维dp。dp[i][j]存的是第一个字符的前i位变到第二个字符串的前j位最少需要几步,因为""变到任意一个另外的字符串,需要的步骤都是另一个字符串的长度,所以先给dp数组赋初值。然后从1遍历到n和m,要等于,所以数组要开大一点。接下来有两种情况
1.word[i-1]==word2[j-1],这样相当于不用做任何操作就匹配上了,它需要的总步长就是dp[i-1][j-1]的大小,只要前面匹配上了最后本来就是匹配的。
2.如果不等于,那么有三种做法,在三种做法中选一个最小的再+1就是dp[i][j]。
最后返回dp[n][m]

class Solution {
public:
    int minDistance(string word1, string word2) {
        //递归会重复计算,dp是循环,不会重复计算,要初始化
        int n = word1.length(), m = word2.length();
        if(n == 0 || m == 0) return m+n;
        //该dp数组代表的是word1前i个字符变到word2前j个字符需要几次操作
        vector<vector<int>> dp(n+1,vector<int>(m+1));
        //二维dp数组基本都是这么初始化
        for(int i = 0; i <= n; ++i){
            dp[i][0] = i;
        }
        for(int j = 0; j <= m; ++j){
            dp[0][j] = j;
        }
        for(int i = 1; i <= n; ++i){
            for(int j = 1; j <= m; ++j){
                if(word1[i-1] == word2[j-1]){
                    //如果1和2最后一位一样,那么就和处理前一位的操作的步数一样
                    dp[i][j] = dp[i-1][j-1];
                }
                else{
                    //这是三种方法,第一种是删去1的一个,第二种是删除2的一个,第三种是1后面添上2的最后
                    //上述三种方法完成后都需要再+1步才能达到相等
                    dp[i][j] = min({dp[i-1][j],dp[i][j-1],dp[i-1][j-1]})+1;
                }
            }
        }
        return dp[n][m];
    }
};

很好很好的动态规划的题目,主要是在动态转移方程中表示出三种操作!!
还有basecase也非常非常重要:dp[0][j]设为j,dp[i][0]设为i,在字符串长度为0时,只有增加新字母这条路
状态定义:dp[i][j]表示从1的前i位变到2的前j位最少几步操作
状态转移方程:如果是abc和bac,如果c相等,只需要对ab和ba进行操作就行了
如果不相等,那么就有三种操作,我们假设全部对1进行操作,
删除操作就是用i-1位去变为j
插入操作就是用i去表示j-1位,因为插进来的那一位肯定和j抵消了
替换操作最简单,i和j抵消,用i-1位表示j-1位,我们取三个操作的最小值并加上1,这个1就是这一步操作

class Solution {
public:
    int minDistance(string word1, string word2) {
        //三种操作,替换,删除,插入
        //dp[i][j]代表从1的前i位到2的前j位最少进行几步操作
        //状态转移方程:如果1[i-1]==2[j-1],那么dp[i][j] = dp[i-1][j-1]
        //如果不相等,那么就有三种操作,重点就是把替换、删除、插入转换成对应方程
        int m = word1.length(), n = word2.length();
        //为什么要把数组开大一位,这样就不用判断边界了
        vector<vector<int>> dp(m+1,vector<int>(n+1));
        //basecase:
        //dp[0][j]设为j,dp[i][0]设为i,在字符串长度为0时,只有增加新字母这条路
        for(int i = 0; i <= m ;++i){
            dp[i][0] = i;
        }
        for(int j = 0; j <= n; ++j){
            dp[0][j] = j;
        }
        for(int i = 1; i <= m; ++i){
            for(int j = 1; j <= n; ++j){
                if(word1[i-1] == word2[j-1]){
                    //如果是abc和bac,如果c相等,只需要对ab和ba进行操作就行了
                    dp[i][j] = dp[i-1][j-1];
                }
                else{
                    //我们假设删除和插入都是在word1上做操作
                    dp[i][j] = min({dp[i-1][j],dp[i][j-1],dp[i-1][j-1]})+1;
                }
            }
        }
        return dp[m][n];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值