代码随想录训练营第56天|583.两个字符串的删除操作、72.编辑距离

583.两个字符串的删除操作72.编辑距离

583.两个字符串的删除操作

思路1–最长公共子序列

对于该题,也许我们可以先求出两个字符串的最长公共子序列,让这两个序列变成这个最长公共子序列即可,这样直接用两个字符串的长度之和减去最长公共子序列长度的两倍即可。
本题就回归到了求最长公共子序列的问题了。
对此,我们已经做过很多求最长公共子序列的题目了。我们只讲思路即可。

对于两个数组中的每一个元素都有两种可能,
两个元素相等于或者不相等,如果两个元素相等,那么我们他的最长公共子序列应该等于左上元素(两个数组分别前一个元素对应的最长公共最序列)+1,这样表示可以得到更长的公共序列。
于此同时,如果两个元素不相等,那么这个元素应该更新为二维数组左边和上边的较大者,继承可能存在的最大子序列长度。

动态规划四部曲。
1.dp数组的含义。dp[ii][jj]表示text1中0-ii-1和text2中0-jj-1中最长公共子序列。
2.dp数组的递推公式。

if(text1[ii-1] == text2[jj-1])
   dp[ii][jj] = dp[ii-1][jj-1]+1;
else
   dp[ii][jj] = max(dp[ii-1][jj],dp[ii][jj-1]);

3.dp数组的初始化。我们令所有第一行和第一列的元素全为0,表示,下标0到下标-1的元素最长公共子序列长度为0,便于进行元素的递推。
4.遍历顺序,先遍历text1或者先遍历text2都可以。

代码
class Solution {
public:
    int minDistance(string word1, string word2) {
        vector<vector<int>>dp(word1.size()+1,vector<int>(word2.size()+1,0));
        int result = 0;
        for(int ii =1;ii<word1.size()+1;ii++)
        {
            for(int jj =1;jj<word2.size()+1;jj++)
            {
                if(word1[ii-1]==word2[jj-1]) 
                {
                    dp[ii][jj] = dp[ii-1][jj-1]+1;
                    result = max(result,dp[ii][jj]);
                }
                else dp[ii][jj] = max(dp[ii-1][jj],dp[ii][jj-1]);
            }
        }
        return word1.size()+word2.size()-2*result;
    }
};

思路2–直接动态规划

对于思路2,我们可以定义dp数组的含义为截止到word1[ii-1]与word2[jj-1]使得两个字符串相等所需要删除的最少元素个数。

因此,对于word1和word2中的元素有两种情况。
1.word1[ii-1]与word2[jj-1]相等,那么我们可以得到dp[ii][jj]应该与dp[ii-1][jj-1]相等,因为word1[ii-1]与word2[jj-1]相等,所以截止到word1[ii-1]与word2[jj-1]删除的元素应该与各个字符串前一个元素删除的元素个数相同。
2.word1[ii-1]与word2[jj-1]不相等,那么,我们可以得到由dp[ii-1][jj]和dp[ii][jj-1]得到,即要不删除word1一个元素,要不删除word2一个元素,这样就会得到dp[ii][jj].
即我们应该取他们之间的最小值dp[ii][jj] = min(dp[ii-1][jj]+1,dp[ii][jj-1]+1);

我们接下来用动态规划四部曲进行分析。
1.dp数组的含义。dp[ii][jj]表示截止到word1[ii-1]与word2[jj-1]使得两个字符串相等所需要删除的最少元素个数。
2.dp数组的递推公式。

if(word1[ii-1]==word2[jj-1]) dp[ii][jj] = dp[ii-1][jj-1];
else dp[ii][jj] = min(dp[ii-1][jj]+1,dp[ii][jj-1]+1);

3.dp数组的初始化。
显然对于dp数组任何一个数组为空时,我们都需要让另一个数组为空,才能让两个数组相等,因此,我们令第一列和第一行等于各自的下标。

        for(int ii =0;ii<word1.size()+1;ii++)
            dp[ii][0] = ii;
        for(int jj =0;jj<word2.size()+1;jj++)
        	dp[0][jj] = jj;

4.dp数组的遍历顺序。先遍历word1和word2都可以。

代码
class Solution {
public:
    int minDistance(string word1, string word2) {
        vector<vector<int>>dp(word1.size()+1,vector<int>(word2.size()+1,0));
        for(int ii =0;ii<word1.size()+1;ii++)
            dp[ii][0] = ii;
        for(int jj =0;jj<word2.size()+1;jj++)
        dp[0][jj] = jj;
        for(int ii =1;ii<word1.size()+1;ii++)
            {
                for(int jj =1;jj<word2.size()+1;jj++)
                {
                    if(word1[ii-1]==word2[jj-1]) dp[ii][jj] = dp[ii-1][jj-1];
                    else
                    dp[ii][jj] = min(dp[ii-1][jj]+1,dp[ii][jj-1]+1);
                }
            }
        return dp[word1.size()][word2.size()];
    }
};

72.编辑距离

对于编辑距离,我们依旧用动态规划的思路来做。
我们定义dp数组的含义为dp[ii][jj]表示以word1[ii-1]结尾和以word2[jj-1]结尾的字符串所需要的最少操作数。

对于两个字符串中的元素,有两种结果,要么相等,要么不相等,因此我们分两种情况进行讨论。
1.如果word1[ii-1]与word2[jj-1]相同,那么我们要获得dp[ii][jj]只需要让dp[ii][jj]等于dp[ii-1][jj-1]即可,因为最后一个元素不用操作,只要前面的元素相同即可。
2.如果word1[ii-1]与word2[jj-1]不相同,那么我们可以对其进行增加、删除或者替换,而增加和删除可以被视为一种运算,因为对一个数组进行添加操作时相当于对另一个元素进行删除操作,所以我们统一视为删除操作。
如果是删除操作,我们可以删除word1中当前访问的元素或者删除word2中当前访问的元素。因此,可以得到dp[ii][jj] = min(dp[ii-1][jj],dp[ii][jj-1])+1;
如果是替换元素,那么我们将最后一个元素替换为另一个字符串中的元素,也就是令dp[ii][jj] = dp[ii-1][jj-1]+1;
因此如果是想要获得最少操作数,我们只需从中取得最小的操作数即可。
dp[ii][jj] = min(dp[ii-1][jj-1],min(dp[ii-1][jj],dp[ii][jj-1]))+1;

动态规划四部曲
1.dp数组的含义。dp数组的含义为dp[ii][jj]表示以word1[ii-1]结尾和以word2[jj-1]结尾的字符串所需要的最少操作数。
2.dp数组的推导公式。

 if(word1[ii-1]==word2[jj-1])    dp[ii][jj] = dp[ii-1][jj-1];
else    dp[ii][jj] = min(dp[ii-1][jj-1],min(dp[ii-1][jj],dp[ii][jj-1]))+1;

3.dp数组的遍历顺序。我们先对word1或者word2遍历都可以。
4.dp数组的初始化。同删除操作一样。我们如果让一个空数组与另一个数组相同时,都需要下标的操作数。即

        for(int ii =0;ii<word1.size()+1;ii++)
            dp[ii][0] = ii;
        for(int jj =0;jj<word2.size()+1;jj++)
        	dp[0][jj] = jj;

代码

class Solution {
public:
    int minDistance(string word1, string word2) {
        vector<vector<int>>dp(word1.size()+1,vector<int>(word2.size()+1,0));
        for(int ii =0;ii<word1.size()+1;ii++)
            dp[ii][0] = ii;
        for(int jj =0;jj<word2.size()+1;jj++)
            dp[0][jj] = jj;
        for(int ii =1;ii<word1.size()+1;ii++)
            for(int jj =1;jj<word2.size()+1;jj++)
                if(word1[ii-1]==word2[jj-1])    dp[ii][jj] = dp[ii-1][jj-1];
                else    dp[ii][jj] = min(dp[ii-1][jj-1],min(dp[ii-1][jj],dp[ii][jj-1]))+1;
        return dp[word1.size()][word2.size()];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值