一个android文本比对app的实现(四)--Hirschberg文本比对算法

28 篇文章 2 订阅

本章所描述的是程序的核心,文本比对算法的实现,文本比对本质上就是字符串的比对,在两个字符串中,找到他们的最长相同子串,例如:

S1 = abcdefg,  S2 = afhctdog; 那么两个字符串的最长相同子串就是:acdg. 在算法导论一书中,最长子串用LCS表示(longest common substring). 寻找lcs 是最为典型的动态规划算法的运用,动态规划也是各大技术公司最为常用的面试内容,我们先了解下,普通的动态规划算法如何寻找lcs.


s1(n) = a1,a2,a3 .... an; s2(m) = b1, b2,b3....bm. (an, bm 分别是构成字符串的单个字母) 要想找到s1, s2 的lcs, 我们设想, 如果 an = bm, 那么s1, s2 的lcs 肯定包含 an, 或 bm.

也就是说: lcs(s1(n), s2(m)) = lcs(s1(n-1), s2(m-1)) + 1. s1 , s2 的最大共同子串相当于s1(n-1) = a1,a2....a(n-1), s2(m-1) = b1, b2, .... b(m-1) 的最大共同字串加上最后一个字符,即a(n), 或 b(m).  如果最后一个字符不一样,那怎办呢,如果最后字符不同,那么我们先找出 s1(n-1), s2(m) 的最大共同子串 lcs1, 然后找出s1(n), s2(m-1) 的最大共同子串lcs2, lcs1 与 lcs2 中,长度最大的那个,就是我们要找的最大共同子串。动态规划最显著的特点是,要想解决总问题,我们先假设,如果次一级的子问题解决了,然后通过次一级子问题的结果,再加上一些简单的操作,就能得到总问题的结果。以LCS 为例,要找到长度为n 和 m 的两个字符串的最大共同子串,我们先找它的次一级字问题的解,即长度为 (n - 1, m - 1), (n - 1, m),  (n, m - 1) 长度的最大共同子串,从这三个子问题的答案中,再做一点简单操作,就可以得到原问题的解。


由于动态规划问题需要用子问题的结果倒推父问题的结果,因此在解决过程中需要存储子问题的结果,回到本问题,我们需要一个二维表lcs[m][n], lcs[i][j] 用于存储S1(i), S2(j) 两个字符串最大共同子串的长度,于是S1(i+1), S2(j+1) 可以轻易的计算出来,如果 a[i+1] == b[j+1] , 那么 lcs[i+1][j+1](也就是S1(i+1), S2(j+1) 两个字符串的最大共同子串的长度) = lcs[i][j] + 1. 如果a[i+1] != b[j+1], 根据我们上面的推论, lcs[i+1][j+1] = max(lcs[i][j+1], lcs[i+1][j]); 由此可见,该算法的时间复杂度是 O(m * n), 空间复杂度是 O(m * n). 具体算法大家可参阅算法导论 动态规划一节。 


如果要在手机上实现该算法,最致命的是算法对空间的需求,假定要比对的文本长度都是一万字符,那么 O(m*n) 等于 一万乘一万,那就是一亿字节,换算成M 就是96,也就是要吃掉手机大概96M的内存,这将大大影响手机系统的性能,因此直接将该算法做到APP里就不合适。


Hirschberg 算法的优势就在于,它将空间复杂度由原来的O(m*n) 改进成 O(m) ,  它利用了分而治之的办法:

要想找到S1(n), S2(m) 的最大共同子串,我先将S1(n) 平分成两部分, S1(1...n/2), S1(n/2+1 ... n), 然后找到一点 t, 将 S2 分成两部分S2(1...t), S2(t+1, ...m), 然后分别计算

S1(1....n/2), S2(1...t) 的lcs, S1(n/2 + 1, ...n), S2(t+1...m) 的lcs, 然后将两个lcs 首尾连接,那么得到的结果就是所要找的最大共同子串。由于在该方法中,我们不需要二维表来存储信息,因此该方法的复杂度由O(M*n) 改进为 O(m)


至于t 如何计算得到,大家可以查找Hirschberg的论文实现,csdn上有相关下载,该文章的名称为 : A Linear space algorithm for computing maximal common substring. 我将算法实现在APP中,大家下载代码看看,基本可以理解算法的实现。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值