编辑距离与滚动数组优化 - 二维动态规划模板

题目:编辑距离

思路

显然,定义 f[i][j] 表示字符串 a 中前 i 个字符到 字符串 b 中前 j 个字符的编辑距离。

那么对于 ai=bj 时,我们对当前位无需进行任何编辑操作,则 f[i][j]=f[i1][j1]

如果 aibj ,那么我们就要对当前位进行编辑:

  • 对于修改操作,我们先要保证 字符串 a 中前 i1 个字符 已经编辑到了 字符串 b 中前 j1 个字符,接下来才把 ai 修改成 bj ,所以转移为 f[i][j]=f[i1][j1]+1
  • 对于插入操作,因为我们是向 ai 后面插入一个 bj ,所以我们要保证 字符串 a 中前 i 个字符 已经编辑到了 字符串 b 中前 j1 个字符,再同时往这两个字符串后插一个 bj ,所以转移为 f[i][j]=f[i][j1]+1
  • 对于删除操作,由于我们是删除 ai 字符,所以我们要保证 字符串 a 中前 i1 个字符 已经编辑到了 字符串 b 中前 j 个字符,这样才能删掉 ai ,所以方程为 f[i][j]=f[i1][j]+1

这三种情况取一个 min 即可。

注意初始化,f[0][0]=0,f[i][0]=i,f[0][j]=j ,因为分别要进行这么多次的删除和插入。

#include <bits/stdc++.h>
using namespace std;
string a,b;
int f[2005][2005];
int main()
{
	cin>>a>>b;
	memset(f,0x3f,sizeof(f));
	f[0][0]=0;
	for(int i=1;i<=a.length();i++)f[i][0]=i;
	for(int i=1;i<=b.length();i++)f[0][i]=i;
	for(int i=1;i<=a.length();i++)
	{
		for(int j=1;j<=b.length();j++)
		{
			if(a[i-1]==b[j-1])f[i][j]=f[i-1][j-1];
			else f[i][j]=min(f[i][j],min(f[i-1][j-1]+1,min(f[i-1][j]+1,f[i][j-1]+1)));
		}
	}
	cout<<f[a.length()][b.length()];
	return 0;
}

滚动数组优化

观察到,如果我们把 dp 数组看作一个网格,那么某一个格子的状态一定是由它左边、上边、左上角的格子的状态转移过来的。

因此,我们就可以用滚动数组优化。

但这里的滚动数组不能用像背包一样的倒序转移,因为这里的转移会用到同级的状态:格子左侧。因此我们先要更新格子左边,才能更新这个格子。所以得从左到右转移。

但从左到右转移会覆盖掉左上角的内容,因此我们要把左上角的东西单独记录一下,然后在赋初值的时候注意一下 f[0]=i 即可。

#include <bits/stdc++.h>
using namespace std;
string a,b;
int f[2005];
int main()
{
	cin>>a>>b;
	f[0]=0;
	for(int i=0;i<=b.length();i++)f[i]=i;
	for(int i=1;i<=a.length();i++)
	{
		int zs=f[0];
		f[0]=i;
		for(int j=1;j<=b.length();j++)
		{
			int tmp=zs;
			zs=f[j];
			if(a[i-1]==b[j-1])f[j]=tmp;
			else f[j]=min(tmp+1,min(f[j]+1,f[j-1]+1));
		}
	}
	cout<<f[b.length()];
	return 0;
}
posted @   KS_Fszha  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示