算法设计与分析:动态规划(3)-序列联配问题(以算代存)

本文参考UCAS卜东波老师算法设计与分析课程撰写

前言

本文内容承接上一次算法设计与分析:动态规划(2) - 序列联配问题(最优对齐方案),讲述高级动态规划的内容。

在前文,我们已经解决了求序列联配中最优对齐的问题。但是完成的方案仍有缺陷:内存消耗过大。对于两个字符串 S m S_m Sm T n T_n Tn,我们计算其最优对齐,需要的数组空间是 O ( m n ) O(mn) O(mn),这在上面的例子中看不出来,但是如果给我们的不是一个短字符串,而是两篇存储量几十KB的文章,让我们做对齐,可想而知,总的内存占用就是几百MB,如果单个内存更大呢?另一方面,时间上由于算法采用两层for循环计算整个二维数组,但最后我们很可能用不到那些多余的内容(数组的边角部分),这就浪费了很多计算时间。显然,这种解决方案就不适用了。

高级动态规划

动态规划对于最优解的获取有着十分显著的效果,但唯一让人诟病的就是其占用大量的存储空间和许多不必要的计算。而高级动态规划弥补了这一缺陷,其节省了存储空间和运行时间。采用方法是以算代存。

应用分治思想减少空间

计算得分

首先思考一个问题,我们每次计算当前格子的分值,考虑的是其左上角三个格子的内容,其余格子都不做考虑,实际上我们每次计算并不需要完整的二维数组的所有数据,只需下如下两列的数据即可:
在这里插入图片描述

一开始,我们初始化第0列(耗费一个数组),当计算第1列的时候,第一个元素-3可以直接初始化得到,对于第一个蓝色框框,左上角三个值都已得到,直接根据递推表达式,得到1,在此基础上进行第二个蓝色框框的计算,以此类推,计算得到前2列的内容

而在计算第2列的内容时,第0列的内容我们已经没必要保存了,因此将第1列的数值保存到前一个数组中,进行下一轮的计算,如下图:
在这里插入图片描述
最终我们数组保存的内容只有最后两列,自然就得到了最后的答案4. 我们容易得到该伪代码如下:
在这里插入图片描述

上面这个方法也告诉我们,如果只关心最优的分值,只需要O(2n)的空间复杂度即可,n是T的长度

  • 回溯得到路径
    上面的方法在计算最终得分上没有问题,但是出现了一个问题,由于最后我们只保存了最后两列,回溯的时候到3,就会发现回溯不动了,因为我们找不到往前的数据了。

    Hirschberg的算法解决了这一问题,它将分治思想应用到了动态规划当中。我们依然从多步决策的角度思考,S如何从T一步步产生?应用分治的思想,我们将S分成两部分,前半部分从T的前一部分产生,后半部分从T的后一部分产生,得到公式如下:
    O P T ( T , S ) = O P T ( T [ 1.. q ] , S [ 1.. n 2 ] ) + O P T ( T [ q + 1.. m ] , S [ n 2 + 1.. n ] ) OPT(T,S) = OPT(T[1..q],S[1..\frac{n}{2}])+OPT(T[q+1..m],S[\frac{n}{2}+1..n]) OPT(T,S)=OPT(T[1..q],S[1..2n])+OPT(T[q+1..m],S[2n+1..n])

    这个公式将S一分为二,它认为S的前半截是从T[1…q]产生的,后半截是T[q+1…m]产生的,q是一个未知量。注意,此式成立的前提是打分是线性加和的。

从后缀匹配到前缀匹配

这里我们需要先了解一个信息,之前我们对S,T动态规划计算是从后往前的,实际上我们从前往后对比计算也是可以的,只不过是把原公式中-1(坐标前移)的操作换成+1(坐标后移)即可。下面是采用前缀匹配得到结果的例子:
在这里插入图片描述

可以看到先对“O”进行递归查询,这部分的内容与上一篇类似,不多赘述,有遗忘的可以回去翻看一下上一篇的推导。、

前面我们应用了分治思想,将S分成两部分,那么我们就可以分别对前半部分采用后缀匹配,后半部分采用前缀匹配,并且只用两个数组存储中间结果,如下:
在这里插入图片描述
注意图中灰色部分的结果,它们是匹配过后的得分结果,也就是“OCUR”和“OCCURRENCE”最终最优匹配分值是-14,“RANCE”和“OCCURRENCE”最终最优匹配分值是-12。我们将这两列的结果加起来,得到中间黄色列的结果,发现中间得到了之前计算的最优分值4!它是由1+3得到的。1是“OCUR”和“OCCUR“相似度,3是”RANCE“和”RENCE“相似度,由于我们采用线性加和得分,1+3的结果就是S与T的相似度!等一下,那这个4出现的位置有什么意义呢?看下面这张图:
在这里插入图片描述
我们发现4将左右分成了上下两部分,而这里的R正好就是q的位置。我们由此可以得到原公式第一次分治如下:
O P T ( ′ O C C U R R E N C E ′ , ′ O C U R R A N C E ′ ) = O P T ( ′ O C C U R ′ , ′ O C U R ′ ) + O P T ( ′ R E N C E ′ , ′ R A N C E ′ ) OPT('OCCURRENCE','OCURRANCE') = OPT('OCCUR','OCUR') +\\ OPT('RENCE','RANCE') OPT(

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值