jzoj 2535. 编辑距离

Description:

编辑距离,又称Levenshtein距离(也叫做Edit Distance),是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。

例如将kitten一字转成sitting:

步骤1:sitten (k->s)    步骤2:sittin (e->i)    步骤3:sitting (->g)

所以kitten和sitting的编辑距离是3。俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。

给出两个字符串a,b,求a和b的编辑距离。

Input:

第1行:字符串a(a的长度 <= 1000)。 第2行:字符串b(b的长度 <= 1000)。

Output:

输出a和b的编辑距离

Sample Input:

kitten
sitting

Sample Output:

3

Solution:

这个问题难点在于有“添加”“删除”这样的操作。我们试试换个角度理解问题,把它看成字符串对齐的问题,我们可以这样理解问题。

给定字符串a和b,我们可以用一种特殊字符促成两个字符串的对齐。我们加的特殊字符是“-”, 我们允许在a和b中任意添加这种特殊字符使得它长度相同,然后让这两个串“对齐”,最终两个串相同位置出现了不同字符,就扣1分,我们要使得这两个串对齐扣分尽量少。

对于例子 我们实际上采取了这样的对齐方式:

A B C F -

D B - F G

注意:如果要对齐,两个“-”相对是没有意义的,所以我们要求不出现这种情况。
那么看一下:

- a,b对应位置都是普通字符,相同,则不扣分。 例如位置2,4
- a,b对应位置都是普通字符,不同,则扣1分。 例如位置1
- a在该位置是特殊字符,b在该位置是普通字符,则扣1分,例如位置5
- a在该位置是普通字符,b在该位置是特殊字符,则扣1分,例如位置3

我们来看看扣分项目对应什么?

- 不扣分,直接对应
- 对应把b中对应位置的字符修改
- 对应在b中删除该字符
- 对应在b中添加该字符

好了,目标明确,感觉像不像最长公共子序列?我们尝试一下:
设f[i][j]表示a的前i位和b的前j位对齐后的最少扣分。

那我们来看看最后一位,对齐的情况

(1) 必须a[i]==b[j], 这时前i–1和j–1位都已经对齐了,这部分肯定要最少扣分。这种情况下最少的扣分是
                                        
(2) 和(1)类似,a[i]!=b[j],这种情况下最少的扣分是
                                        
(3) a的前i位和b的前j-1位已经对齐了,这部分扣分也要最少。这种情况下最少的扣分是
        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        
(4) a的前(i-1)位已经和b的前j位对齐了,这部分扣分要最少。这种情况下最少的扣分是
                                        

具体f[i][j]取什么值,显然是要看哪种情况的扣分最少。

为了方便,我们定义函数same(i,j)表示如果a[i]==b[j]则返回0,否则返回1。则状态转移方程为:
        ​​​​​​​        

初始值:,

CODE:

#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <algorithm>

#pragma GCC optimize("-Ofast")
#define N 1000000
#define rg register
#define ll long long
#define o3 __attribute__((optimize("-O3")))

using namespace std;
const int M = 1000;
char a[M + 5], b[M + 5];
int f[M][M], ans;
o3 inline int same(int x, int y) {
	if (a[x] == b[y]) {
		return 0;
	} else {
		return 1;
	}
}
o3 int main () {
	cin>>a + 1;
	cin>>b + 1;
	memset(f, 1e9, sizeof(f));
	int la = strlen(a + 1), lb = strlen(b + 1);
	for (int i = 0; i <= la; ++ i) {
		f[i][0] = i;
	}
	for (int j = 0; j <= lb ; ++ j) {
		f[0][j] = j;
	}
	for (int i = 1; i <= la; ++ i) {
		for (int j = 1; j <= lb; ++ j) {
			f[i][j] = min(f[i - 1][j - 1] + same(i, j), min(f[i - 1][j] + 1, f[i][j - 1] + 1));
		}
	}
	printf("%d", f[la][lb]);
} 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值