字符串线性DP-洛-编辑距离
P2758 编辑距离
题目描述
设 \(A\) 和 \(B\) 是两个字符串。我们要用最少的字符操作次数,将字符串 \(A\) 转换为字符串 \(B\)。这里所说的字符操作共有三种:
- 删除一个字符;
- 插入一个字符;
- 将一个字符改为另一个字符。
\(A, B\) 均只包含小写字母。
输入格式
第一行为字符串 \(A\);第二行为字符串 \(B\);字符串 \(A, B\) 的长度均小于 \(2000\)。
输出格式
只有一个正整数,为最少字符操作次数。
输入输出样例 #1
输入 #1
sfdqxbw
gfdgw
输出 #1
4
说明/提示
对于 \(100 \%\) 的数据,\(1 \le |A|, |B| \le 2000\)。
思路
其实一开始dp数组的想法大致正确,只是状态转移方程不知道怎么写。不要真想着改变字符串,只是想着处理到某个位置用什么操作,是怎么得到的。不要想着破坏a的结构,否则要存很多中间状态,很复杂,只需省略中间,保存结果。但是要注意初始化,这样可以省去好多为0的特判。
转移方程:
1.删除:删掉 A [i] → dp[i-1][j] + 1 2.插入:在 A 末尾补上 B [j] → dp[i][j-1] + 1
3.替换:如果 A[i]==B[j]:不用改 → dp[i-1][j-1]; 如果不等:需要修改一次 → dp[i-1][j-1] + 1
删是看a自己前面的,增是看b前面的是否满足。
代码;
点击查看代码
#include <bits/stdc++.h>
using namespace std;
string a,b;
int dp[2010][2010]; //处理a前i个字符得到b前j个字符
int main()
{
cin>>a>>b;
memset(dp,0x3f,sizeof(dp));
for(int i = 0;i <= b.size();i++) dp[0][i] = i; //增,处理i=0
for(int i = 0;i <= a.size();i++) dp[i][0] = i; //删,处理j=0
for(int i = 1;i <= a.size();i++)
{
for(int j = 1;j <= b.size();j++)
{
//1.删
dp[i][j] = min(dp[i][j],dp[i-1][j] + 1);
//2.增
dp[i][j] = min(dp[i][j],dp[i][j-1] + 1);
//3.改
if(a[i-1] == b[j-1]) dp[i][j] = min(dp[i][j],dp[i-1][j-1]); //下标注意一定要减1
else dp[i][j] = min(dp[i][j],dp[i-1][j-1]+1);
}
}
//cout<<dp[1][1]<<endl;
cout<<dp[a.size()][b.size()];
return 0;
}

浙公网安备 33010602011771号