最小编辑距离算法以及例题解析

最小编辑距离

首先我们先了解一下什么是最小编辑距离

假设我们有两个字符串T, S,我们的目标是把T和S变成一样的字符串
那么我们对于两个字符串某个位置的字符有以下操作
1.如果当前位置字符相同,那么什么都不做
2.如果当前位置字符不相同,我们可以删除T中的一个字符
3.如果当前位置字符不相同,我们可以删除T中的一个字符
4.如果当前位置字符不相同,我们可以更改T中的一个字符为S中的字符
5.如果当前位置字符不相同,我们可以更改S中的一个字符为T中的字符

模板

int dp[1005][1005];
 
int EditDis(string a, string b)
{
	int maxnum = max(a.size(), b.size()) + 1;
    for(int i=1;i<=a.size()+1;i++)
        for(int j=1;j<=b.size()+1;j++)
            dp[i][j] = maxnum;
    for(int i=1;i<=a.size()+1;i++)
        dp[i][0] = i;
    for(int j=1;j<=b.size()+1;j++)
        dp[0][j] = j;
    for(int i=1;i<=a.size()+1;i++)
    {
        for(int j=1;j<=b.size()+1;j++)
        {
            int flag;
            if(a[i]==b[j])
                flag=0;
            else
                flag=1;
            dp[i][j]=min(dp[i-1][j]+1,min(dp[i][j-1]+1,dp[i-1][j-1]+flag));
        }
    }
    return dp[a.size()+1][b.size()+1];
}

初始化很常规,模板的难点在于递推式

根据上述几种操作我们有以下的递推式
dp[i-1][j]+1:删掉字符串a最后一个字符a[i]
dp[i][j-1]+1:表示给字符串添加b最后一个字符
dp[i-1][j-1]+flag表示改变,相同则不需操作次数,不同则需要,用flag记录,flag为0说明什么也不做,如果为1说明要修改字符

有时还会遇到以下两种情况
dp[i-1][j]:a中前i-1个字符与b中前j个字符的匹配结果
dp[i][j-1]:a中前i个字符与b中前j-1个字符的匹配结果

加上这两个情况后dp数组更新就变为

dp[i][j]=min(min(dp[i-1][j]+1,min(dp[i][j-1]+1,dp[i-1][j-1]+flag)), min(dp[i-1][j], dp[i][j-1]));

例题

例题来源于蓝桥杯官网的练习题

最优包含

题意

我们称一个字符串 S 包含字符串 T 是指 T 是 S 的一个子序列,即可以从字符串 S 中抽出若干个字符,它们按原来的顺序组合成一个新的字符串与 T 完全一样。
给定两个字符串 S 和 T,请问最少修改 S 中的多少个字符,能使 S 包含 T ?
其中:
1 ≤ ∣ T ∣ ≤ ∣ S ∣ ≤ 1000 1 \leq |T| \leq |S| \leq 1000 1TS1000

输入输出样例

输入:

ABCDEABCD
XAABZ

输出:

3 

代码

#include<cstring>
#include<iostream>

using namespace std;
char a[1001], b[1001];
int dp[1001][1001];
int n, m;

int main() {
    cin >> a + 1 >> b + 1;
    n = strlen(a + 1);
    m = strlen(b + 1);
    memset(dp, 0x3f3f3f3f, sizeof dp);//初始化dp数组,无穷大

    dp[0][0] = 0;
    for (int i = 1; i <= n; i++) {
        dp[i][0] = 0;
        for (int j = 1; j <= m; j++) {
            if (a[i] == b[j]) {
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1] + 1);
            }
        }
    }
    cout << dp[n][m] << endl;
    return 0;
}

这里的做法比较简单,因为这里只是进行修改,并且是用第二个字符串匹配第一个字符串,所以只包含两种情况

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艾醒(AiXing-w)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值