一本通 1276:【例9.20】编辑距离 C++

看完题目后,整个人都懵了,这题咋整?

哎呀,知道知道,用动态规划做

不要慌,我们慢慢分析....


目录

做题前须知

状态转移

如果 a[i] == b[j]

如果 a[i] != b[j]

做删除操作

做插入操作

做替换操作

初始化

输出

最终代码


做题前须知

读完题发现要输出  让A字符串变为B字符串最少要几步

变化方式有3种  👇

  • 删除一个字符
  • 插入一个字符
  • 改变一个字符

注意啦!

只能改变A字符串

只能改变A字符串

只能改变A字符串!!!!

重要的事说3遍😁


状态转移

这题 dp[i][j] 代表 让a[1~i]变为b[1~j]字符串最少要几步 相信这个大家肯定都知道

那如何状态转移?

如果 a[i] == b[j]

假设每个字符串后面都是x

A  |-----------------------| x

B  |-----------------------| x

像这样👆      那俩 x 就根本不用管,所以操作数就等于dp[i-1][j-1]

第一个转台转移方程闪亮登场👇

dp[i][j] = dp[i-1][j-1]


如果 a[i] != b[j]

假设一个字符串后面是x,一个字符串后面是y

做删除操作

|--------------------------|  x

|-----------------------| y

我们是不是只要让a[1 ~ i-1] 和 b[1 ~ j] (淡蓝色部分) 相等然后再删除 ‘x' 就行了,所以...

dp[i][j] = dp[i-1][j] + 1

 为啥还加个1啊,删掉那个 ’x' 不就是一步嘛?所以还要 +1

做插入操作

|----------------------|  x

|-------------------------| y

我们是不是只要让a[1 ~ i] 和 b[1 ~ j-1] (淡蓝色部分) 相等然后再在A串结尾添加 'y' 就行了,所以...

 dp[i][j] = dp[i][j-1] + 1

做替换操作

|------------------------| x

|------------------------| y

我们是不是只要让a[1 ~ i-1] 和 b[1 ~ j-1] (淡蓝色部分) 相等然后再将A串结尾的 'x' 替换成 'y' 就行了,所以...

 dp[i][j] = dp[i-1][j-1] + 1

最后,只要将三个值算出来 再取个最小值 就可以赋值到dp[i][j]了

总结起来dp[i][j]的人生大概就是这样👇

                   /   a[i]==b[j]                    dp[i-1][j-1]

dp[i][j] ------                                   /   dp[i-1][j]       删除

                   \    a[i]!=b[j]   --min--|     dp[i][j-1]       插入

                                                     \  dp[i-1][j-1]    替换


初始化

状态方程考虑完了,接下来我们来想一想怎么初始化

一个空串变为b[1~i]要i步,为什么,一直在结尾插入不就完了

同样让a[1~i]变为空串也要i步,那i步不就是一直删除吧

所以可以得到

dp[i][0] = i

dp[0][i] = i


输出

cout << dp[n][m];

一痛分析下来,相信你已经会写了

还是不会的小伙伴跟我来!

最终代码

//【例9.20】编辑距离
#include <iostream>
#include <cstring>

using namespace std;

const int N = 2005;

int dp[N][N];
char a[N], b[N];

int main() {
	cin >> a + 1 >> b + 1;
	int n = strlen(a + 1), m = strlen(b + 1);

	for (int i = 0; i <= n; i ++)
		dp[i][0] = i;
	for (int i = 0; i <= m; i ++)
		dp[0][i] = i;

	for (int i = 1; i <= n; i ++) {
		for (int j = 1; j <= m; j ++) {
			if (a[i] == b[j]) //结尾相同
				dp[i][j] = dp[i - 1][j - 1];
			else {
				dp[i][j] = dp[i - 1][j] + 1; //删除
				dp[i][j] = min(dp[i][j], dp[i][j - 1] + 1); //插入
				dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + 1); //替换
				//在 删除 插入 替换 中 选出最优解
			}
		}
	}

	cout << dp[n][m];
	return 0;
}
/*
【输入样例】
sfdqxbw
gfdgw
【输出样例】
4
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值