最长公共子序列与编辑距离动态规划原理分析
来源:互联网 发布:淘宝猫粮店推荐 编辑:程序博客网 时间:2024/06/15 10:17
前段时间看过最长公共子序列的动态规划算法,这两天又看到了编辑距离的动态规划算法,感觉两者有很相似的地方,而状态转移方程又不十分直观,所以打算把其原理记录下来,以防以后忘记。
先看最长公共子序列,记两个序列分别为a[m],b[n].其状态转移方程如下:
从中我们可以看出分成两种情况,第一种是a[i]=b[j],第二种是a[i]!=b[j]
1.a[i]=b[j]。这种情况还是比较显然的,既然a[i]=b[j]了,我们就可以将a[0-i],b[0-j]如下排列:
a[0] a[1] ..... a[i-1] a[i]
b[0] ....b[j-1]b[j]
这时候我们就把a[i],b[j]从上面这两个个序列中去掉,然后就变成了a[0-(i-1)],b[0-(j-1)]这种情况了,而这种情况我们已经知道c[i-1][j-1]了,所以c[i][j]就比c[i-1][j-1]多了一项a[i]与b[j]匹配的情况,所以c[i][j]=c[i-1][j-1]+1。
当然有人可能就奇怪了,为啥能一定保证a[i]b[j]匹配时的情况一定是公共子序列最大的情况,如果a[i]与b[j]不匹配说不定c[i][j]更大呢。那我们就看一下这种情况:
假设在某种匹配方式下,a[i]与b[j]不匹配。这时a[i]与b[0-(j-1)]的某个数匹配,或b[j]与a[0-(i-1)]中的某个数匹配(如果这两种情况都不发生,说明a[i]、b[j]都不在最长公共子序列k中,这时如果把a[i]与b[j]匹配的这一组加入k中得到K,显然K>k,这说明k不是最长公共子序列,产生了矛盾)。不妨设发生了a[i]与b[0-(j-1)]的某个数匹配的情况,如下
a[0] a[1] ..... a[i-1] a[i]
b[0] ....b[j-k-1]b[j-k] b[j-k+1] .....b[j]
这时候,a[i-1]就只能与b[j-k]之前的数匹配了。那么,在这种匹配方式下的c`[i][j]=c[i-1][j-k-1]+1。而根据状态转移方程,c[i-1][j-1]>=c[i-1][j-k-1](使用数学归纳法),所以,a[i]b[j]匹配的c[i][j]>=c`[i][j].这说明,我们假设中的a[i]与b[j]不匹配的匹配方式不会是唯一最优的方式,而a[i]b[j]匹配的匹配方式则是一种最优的匹配方式。
2.a[i]!=b[j]。
这时候a[i]b[j]就不可能再匹配上了。然而在求a[0-i]b[0-j]的最长公共子序列时,我们还可以人为地分为3种情况:
1、a[i]不在最长公共子序列中
2. b[j]不在最长公共子序列中
3.a[i]和b[j]都不在最长公共子序列中.
先看情况1、2。12这两种情况本质上是一种,所以不妨设是第二种情况,这时候最长公共子序列中就没有b[j]什么事了,显然a[0-i]b[0-j]的最长公共子序列与a[0-i]b[0-(j-1)]的最长公共子序列是完全一样的。所以 c[i][j]=c[i][j-1]
再看情况3.如果在a[0-i]b[0-j]最长公共子序列中b[j]不存在,说明b[j]对于其最长公共子序列没有任何影响,那么c[i][j]=c[i][j-1]。同理,c[i][j]=c[i-1][j]
这样这三种情况都讨论完了,但是在真正执行的时候我们可不知道到底是哪种情况最好。那就把三种情况都算出来,取三种情况中最大的,即c[i][j]=max(c[i-1][j],c[i][j-1])
那么情况1、2综合起来,加上i、j=0的情况,就得到了上图中的状态转移方程.
其状态转移方程如下
- if i == 0 且 j == 0,edit(i, j) = 0
- if i == 0 且 j > 0,edit(i, j) = j
- if i > 0 且j == 0,edit(i, j) = i
- if i ≥ 1 且 j ≥ 1 ,edit(i, j) == min{ edit(i-1, j) + 1, edit(i, j-1) + 1, edit(i-1, j-1) + f(i, j) },当第一个字符串的第i个字符不等于第二个字符串的第j个字符时,f(i, j) = 1;否则,f(i, j) = 0。
第四种情况说明对a[0-i]的最少操作次数都是在对a[0-(i-1)]操作的基础上进行的:edit(i-1, j) + 1相当于a[0-i]先删去a[i]变成a[i-1]后再与b[0-j]匹配,edit(i, j-1) + 1相当于a[0-i]添加了一个a[i+1]=b[j]后再将a[0-i]与b[0-(j-1)]匹配(a添加b[j]等效于b删去b[j]),edit(i-1, j-1) + f(i, j)相当于使a[i]替换为b[j]后,继续进行a[i-1]到p[j-1]的操作。
同样的问题,为什么这样做操作次数就会最少呢?
a[i]=b[j]的情况比较显然,分析过程同下面,略过。
a[i]!=b[j]时,假设存在某种操作方式m,使得edit(m)=edit(i,j)<min{ edit(i-1, j) + 1, edit(i, j-1) + 1, edit(i-1, j-1) + f(i, j) }
那么我们来看一下在操作m后 变换为b[j]的a[p]的来源。
1、若a[p]来自于向a中插入了一个新数aa,那么我们采取操作m来变换a[0-i],但去掉添加aa的过程,那么最终的效果就是a[0-i]变为b[0-(j-1)]。这时候这种操作的操作次数edit`(i,j-1)=edit(m)-1<edit(i,j-1),这样就产生矛盾了(因为按照前提,不可能存在操作次数比edit(i,j-1)还少的从a[0-i]变化到b[0-(j-1)]的过程),说明若a`[j]来自于向a中插入了一个新数aa,不可能存在这种操作m
2、若a[p]来自于a[k](k<i,a[k]=b[j])(a[k]也可能是由替换产生的),即:将a[k]以后的数都删去。那么,显然对a[0-(i-1)]执行操作m,但去掉"删除a[i]"这一操作,最终的结果就是a[0-(i-1)]变为b[0-j]。这时候edit`(i-1,j)=edit(m)-1<edit(i,j-1),矛盾。
3。、若a[p]来自于a[i]替换为b[j],那么,显然对a[0-(i-1)]执行操作m,但去掉"替换a[i]"这一操作,最终的结果就是a[0-(i-1)]变为b[0-(j-1)]。这时候edit`(i-1,j)=edit(m)-1<edit(i-1,j-1),矛盾。
综上123所述,不可能存在比min{ edit(i-1, j) + 1, edit(i, j-1) + 1, edit(i-1, j-1) + f(i, j) }更少的操作次数,否则就会产生矛盾。同时,根据红色部分的分析,我们知道,通过min{ edit(i-1, j) + 1, edit(i, j-1) + 1, edit(i-1, j-1) + f(i, j) }这一公式计算出的最小编辑次数是有方法来实际进行执行的。
上面就是最长公共子序列和编辑距离的动态规划方程的原理分析,比较繁琐,感觉发明算法的人思路应该不是这样,但对理解方程应该也有一些帮助。同样问题的还有最长公共子串问题,个人感觉还是比较容易理解,就不再具体分析。
- 最长公共子序列与编辑距离动态规划原理分析
- 动态规划之最长公共子序列和编辑距离
- 动态规划——最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串最小编辑距离日记整理
- 编辑距离和最长公共子序列(动态规划经典题)
- 编辑距离与最长公共子序列总结
- 【动态规划基础篇】【矩阵取数/最大字段和/最长公共子序列(LCS)/编辑距离/最长上升子序列(LIS)】
- 最长公共子序列求解:递归与动态规划方法
- 动态规划学习与实例(2) 最长公共子序列
- 最长公共子序列求解:递归与动态规划方法
- 最长公共子序列求解:递归与动态规划方法
- 最长公共子序列求解:递归与动态规划方法
- 最长公共子序列求解:递归与动态规划方法
- 最长公共子序列求解:递归与动态规划方法
- 最长公共子序列求解:递归与动态规划方法
- 递归与动态规划---最长公共子序列问题
- 最长公共子序列&&最长公共子串---[动态规划]
- 动态规划-最长公共子序列、最长公共子串
- 编辑距离,最长公共子序列,最长公共子串,最长递增子序列
- python 标准库之os
- C语言经典算法15
- BOM编程-Document
- leetcode 439. Ternary Expression Parser
- 安卓最新版本及基础知识
- 最长公共子序列与编辑距离动态规划原理分析
- php 递归与迭代区别
- C语言经典算法16
- oracle sql语句解析过程
- Linux安装搜狗输入法
- BOM编程-ELEMENT
- JS学习(三)
- 【回归分析】[5]--多元线性回归对参数的F检验
- linux系统编程之信号(二):一些信号发送函数和不同精度的睡眠