算法复习——动态规划篇之编辑距离问题

算法复习——动态规划篇之编辑距离问题

以下内容主要参考中国大学MOOC《算法设计与分析》,墙裂推荐希望入门算法的童鞋学习!

1. 问题背景

​ 在输入法自动更正时,像kittchen、kithen和kitchem等会被自动更正为kitchen,而不会被更正为sitting等其他单词。那么,问题就是如何衡量序列的相似程度?

​ 我们可以用编辑操作来度量两个序列的相似程度。一个字符串A可以通过一系列编辑操作转变成另一个字符串B,假设我们只允许三种编辑操作:删除、插入和替换。如下图所示,kittchen、kithen和kitchem等都只需要通过一次操作就可以变成kitchen。

在这里插入图片描述

​ 那么,像kittchen要经过几次编辑操作会变成sitting呢?比如,有以下两种方案。

在这里插入图片描述

​ 问题在于如何求出最少的编辑操作数(最小编辑距离)?

2. 问题定义

编辑距离问题(Minimum Edit Distance, MED)

输入:

  • 长度为 n n n的字符串 s s s,长度为 m m m的字符串 t t t

输出:

  • 求出一组编辑操作 O = < e 1 , e 2 , … , e d > O=<e_1, e_2, \dots, e_d> O=<e1,e2,,ed>,令 m i n ∣ O ∣ min|O| minO

    s . t . s.t. s.t.字符串 s s s经过 O O O的操作后满足 s = t s=t s=t

3. 动态规划

3.1 问题结构分析

  • 给出问题表示

    • D [ i , j ] D[i, j] D[i,j]:字符串 s [ 1.. i ] s[1..i] s[1..i]变为 t [ 1.. j ] t[1..j] t[1..j]的最小编辑距离

在这里插入图片描述

  • 明确原始问题

    • D [ n , m ] D[n, m] D[n,m]:字符串 s [ 1.. n ] s[1..n] s[1..n]变为 t [ 1.. m ] t[1..m] t[1..m]的最小编辑距离

3.2 递推关系建立

3.2.1 分析最优(子)结构

​ 在这个问题中,我们仍然考察的是末尾元素,但是我们只关心删除、插入和替换来操作 s s s串。

​ 删除是删除 s s s串的最后一位,这是有助于我们从 s s s串变成 t t t串的,如下图所示,所以我们进一步需要关心的是如何从 s [ 1.. i − 1 ] s[1..i-1] s[1..i1]变成 t [ 1.. j ] t[1..j] t[1..j],因此 D [ i , j ] = D [ i − 1 , j ] + 1 D[i, j] = D[i-1, j] + 1 D[i,j]=D[i1,j]+1

在这里插入图片描述

​ 插入是在 s s s串的最后插入一位,且最后插入的元素一定是 t t t串的最后一位,如下图所示,所以我们进一步需要关心的是如何从 s [ 1.. i ] s[1..i] s[1..i]变成 t [ 1.. j − 1 ] t[1..j-1] t[1..j1],因此 D [ i , j ] = D [ i , j − 1 ] + 1 D[i, j]=D[i, j-1] + 1 D[i,j]=D[i,j1]+1

在这里插入图片描述

​ 替换是把 s s s串的最后一位替换为 t t t串的最后一位,如下图所示,但如果 s [ i ] = t [ j ] s[i]=t[j] s[i]=t[j],就不需要替换,则 D [ i , j ] = D [ i − 1 , j − 1 ] D[i, j]=D[i-1, j-1] D[i,j]=D[i1,j1];否则,需要替换,而且我们进一步需要关心的是如何从 s [ 1.. i − 1 ] s[1..i-1] s[1..i1]变成 t [ 1.. j − 1 ] t[1..j-1] t[1..j1],因此 D [ i , j ] = D [ i − 1 , j − 1 ] + 1 D[i, j]=D[i-1, j-1]+1 D[i,j]=D[i1,j1]+1

在这里插入图片描述

3.2.2 构造递推公式

​ 综合上面三种方式,我们可以得到递推公式
D [ i , j ] = m i n { D [ i − 1 , j ] + 1 , D [ i , j − 1 ] + 1 , D [ i − 1 , j − 1 ] + { 0 , i f   s [ i ] = t [ j ] 1 , i f   s [ i ] ≠ t [ j ] D[i,j]=min\left\{ \begin{array}{rcl} D[i-1, j]+1,& &\\ D[i, j-1]+1,& &\\ D[i-1, j-1]+&\left\{ \begin{array}{rcl} 0, & &{if\ s[i]=t[j]}\\ 1, & &{if\ s[i] \neq t[j]} \end{array} \right. \end{array} \right. D[i,j]=minD[i1,j]+1,D[i,j1]+1,D[i1,j1]+{0,1,if s[i]=t[j]if s[i]=t[j]

3.3 自底向上计算

3.3.1 确定计算顺序
  • 初始化:

    • D [ i , 0 ] = i D[i, 0]=i D[i,0]=i(把长度为 i i i的串变为空串至少需要 i i i次删除操作)
    • D [ 0 , j ] = j D[0, j]=j D[0,j]=j(把空串变为长度为 j j j的串至少需要 j j j次插入操作)
  • 递推公式:
    D [ i , j ] = m i n { D [ i − 1 , j ] + 1 , D [ i , j − 1 ] + 1 , D [ i − 1 , j − 1 ] + { 0 , i f   s [ i ] = t [ j ] 1 , i f   s [ i ] ≠ t [ j ] D[i,j]=min\left\{ \begin{array}{rcl} D[i-1, j]+1,& &\\ D[i, j-1]+1,& &\\ D[i-1, j-1]+&\left\{ \begin{array}{rcl} 0, & &{if\ s[i]=t[j]}\\ 1, & &{if\ s[i] \neq t[j]} \end{array} \right. \end{array} \right. D[i,j]=minD[i1,j]+1,D[i,j1]+1,D[i1,j1]+{0,1,if s[i]=t[j]if s[i]=t[j]
    在这里插入图片描述

3.3.2 依次计算问题

在这里插入图片描述

3.4 最优方案追踪

3.4.1 记录决策过程

​ 用追踪数组 R e c Rec Rec来记录子问题来源。

在这里插入图片描述

3.4.2 输出最优方案

​ 根据数组 R e c Rec Rec,输出最少编辑操作。

4. 伪代码

Minimum-Edit-Distance(s, t)

输入:字符串 s s s t t t

输出: s s s t t t的最小编辑距离

n ← length(s)
m ← length(t)
新建D[0..n, 0..m],Rec[0..n,0..m]两个二维数组
// 初始化
for i ← 0 to n do
	D[i, 0] ← i
    Rec[i, 0] ← "U"
end
for j ← 0 to m do
	D[0, j] ← j
	Rec[0, j] ← "L"
end
// 动态规划
for i ← 1 to n do
	for j ← 1 to m do
		c ← 0
		if s[i] != t[j] then
			c ← 1
		end
		replace ← D[i-1, j-1] + c
		delete ← D[i-1, j] + 1
		insert ← D[i, j-1] + 1
		if replace = min{delete, insert, replace} then
			D[i, j] ← D[i-1, j-1] + c
			Rec[i, j] ← "LU"
		end
		else if insert = min{delete, insert, replace} then
			D[i, j] ← D[i, j-1] + 1
			Rec[i, j] ← "L"
		end
		else
			D[i, j] ← D[i-1, j] + 1
			Rec[i, j] ← "U"
		end
	end
end

Print-MED(Rec, s, t, i, j)

输入:矩阵Rec,字符串s,t,位置索引i和j

输出:操作序列

if i = 0 and j = 0 then
	return NULL
end
if ReC[i, j] = "LU" then
	Print-MED(Rec, s, t, i-1, j-1)
	if s[i] = t[j] then
		print "无需操作"
	end
	else
		print "用t[j]替换s[i]"
	end
end
else if Rec[i, j] = "U" then
	Print-MED(Rec, s, t, i-1, j)
	print "删除s[i]"
end
else
	Print-MED(Rec, s, t, i, j-1)
	print "插入t[j]"
end

​ 该算法的时间复杂度是 O ( m n ) O(mn) O(mn)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值