1 前言

这个4个算法比较相似,并且有以下相同点和不同点

2 异同点

以str1 = "ABCDEF" , str2="ZABCDZE" 为例

相同点:

1、都是在字符串上得到某个目标;2、算法的核心都是动态规划的思想。

不同点:

1、目标不同,其中最大公共字符串是最大连续的子序列,例如:最大公共字符串是"ABCD" ,长度为4。而最大公共子序列是"ABCDE",长度为5。

2、编辑距离,是求从一个字符串str1到另一个字符串str2的变动的最小次数,其中变动只在一个字符串上发生,变动包括三个动作:删除,插入,更改。

3、Myers可能听得比较少,但是作为程序员应该都用过,因为SVN和GIT的版本比对算法,diff是用的这个算法,他可以比较全面的寻找到每一个节点的异同。虽然是动态规划,但是它跟前面的三个算法的遍历方式不同,这也是本质的不同,这里提一下,后面详述。补充一句,对于

不废话了,下面来直接看这三个的实现过程。

3 最大公共字符串(LCS)

最大公共字符串是最大的连续的公共的字符串的长度,既然是动态规划,必然是要有递推式。先写出来。

以str1 = "ABCDEF" , str2="ZABCDZE" 为例, 为 和 的最大公共字符串。则递推如下:

下面开始写代码

def longer_common_string(str1, str2):"""最大公共字符串 实现"""len1 = len(str1)len2 = len(str2)max_lcs_len = 0max_len_axis = (0, 0)lcs_matrix = [[0 for j in range(len2+1)] for i in range(len1+1)]for i, char_1 in enumerate(str1):for j, char_2 in enumerate(str2):if char_1 == char_2:lcs_matrix[i+1][j+1] = lcs_matrix[i][j] + 1if lcs_matrix[i+1][j+1] > max_lcs_len:max_lcs_len = lcs_matrix[i+1][j+1]max_len_axis = (i, j)else:lcs_matrix[i+1][j+1] = 0return max_lcs_len, max_len_axis
str1 = "ABCDEF"
str2 = "ZABCDZE"
lcs_len, axis = longer_common_string(str1, str2)
print(lcs_len)
print(axis)# print result
# 4
# (3, 4)

得到结果 lcs_len = 4, axis =(3,4),表示最大公共子序列在str1 索引为3的位置结束,在str2索引为4的地方结束。

4 最大公共子序列(LCQ)

子序列可以是非连续的字符串,因此 lcq >= lcs 恒成立。对于递推关系,则要所有改变了, 以str1 = "ABCDEF" , str2="ZABCDZE" 为例, 为 和 的最大公共字符串。则递推如下:

下面开始写代码

def longer_common_sequence(str1, str2):"""最大公共子序列 实现"""len1 = len(str1)len2 = len(str2)max_lcq_len = 0max_len_axis = (0, 0)lcq_matrix = [[0 for j in range(len2+1)] for i in range(len1+1)]for i, char_1 in enumerate(str1):for j, char_2 in enumerate(str2):if char_1 == char_2:lcq_matrix[i+1][j+1] = lcq_matrix[i][j] + 1if lcq_matrix[i+1][j+1] > max_lcq_len:max_lcq_len = lcq_matrix[i+1][j+1]max_len_axis = (i, j)else:lcq_matrix[i+1][j+1] = max(lcq_matrix[i+1][j], lcq_matrix[i][j+1])return max_lcq_len, max_len_axisstr1 = "ABCDEF"
str2 = "ZABCDZE"
lcq_len, axis = longer_common_sequence(str1, str2)
print(lcq_len)
print(axis)# print result
# 5
# (4, 6)

结果意思与LCS相同,不再赘述。

5 编辑距离Edit Distance

目标:使得str1通过 替换、插入,删除 三种操作,以最小的操作数,变为str2

编辑距离与LCS,LCQ不同之处在在于,编辑距离是找不同,前两者是找相同,在某种意义上也是殊途同归。

先上递推公式,再解释

ED代表编辑距离,表示的编辑距离。下面来一行一行的解释:

5.1   0==min(i,j)

初始化,当i为0,或者j为0时,编辑距离就等于i和j中的最大值。

5.1.1,必然有一个为空字符串,假设,那么自然,从空字符串到需要次插入操作

5.2   Others

当 i不等于0且j不等于0时,选取三种操作 替换、删除 完成我们目标

 5.2.1 这里说的是替换,用 str2[j]替换str1[i]时。而当str1[i]==str2[j]时,是不需要替换的,所以此时d=0。

5.2.2  , 相对于多了一个str1[i],对应的操作是删除。

5.2.2  相对于,少了一个str2[j],对应操作是增加。

最后再从 增加,删除,插入 三个操作中取得最小值。

代码如下:

def edit_distance(str1, str2):len1 = len(str1)len2 = len(str2)ed_matrix = [[max(i, j) if 0 == min(i,j) else 0 for j in range(len2+1)] for i in range(len1+1)]for i, char_1 in enumerate(str1):for j, char_2 in enumerate(str2):if char_1 == char_2:d = 0else:d = 1replace_dist = ed_matrix[i][j] + dinsert_dist = ed_matrix[i-1][j] + 1delete_dist = ed_matrix[i][j-1] + 1ed_matrix[i+1][j+1] = min(replace_dist, insert_dist, delete_dist)return ed_matrix[-1][-1]
str1 = "ABCDEF"
str2 = "ZABCDZE"
ed = edit_distance(str1, str2)
print(ed)
# print
# 3

终于把上面的三款砖抛完了,该引出玉了

6、Myers

6.1 遍历方式不同

上面三种的动态规划,都是以 x,y轴作为遍历方便的,而Myers是以 x+y 和 x-y的方向上做遍历的,这样有个好处,就是在碰到连续的 str1[i]==str2[j]可以以时间复杂度为1的方法,走快车道。

LCS,LCQ,ED的遍历方式

Myers的遍历方式

6.2 举例说明Myers路径

以str1 = "ZABCDZE" , str2="ABCDEF"为例,说明路径方式

先来说一个目标,将str1通过约束的规则变为str2,但是要求操作次数最小,规则如下:

只能有2种操作,1、删除 str1的某个字符;2、插入str2某个字符。或者保留二者相同的字符。且每个字符串中的每个字符无论是删除,插入,还是保留相同(滑滑梯操作),皆只能使用一次。而 操作次数=删除次数 + 插入次数。在图中,横向代表删除str1中的某个字符,纵向路径代表插入str2中某字符,而斜线代表保留相同的某字符。

myers路径

红色箭头代表第一步,黄色箭头代表第二步,蓝色箭头代表第三步,所有的路径操作次数都是3,本来2^3=8一共八条路径,由于其中有一条超出界外了,所以一共7条,我们现在来依次看看八条路是怎么走的,为什么有的快,有的慢。

第1条路径:[(0,0), (4,5), (5,7),(6,7)]

第2条路径:[(0,0), (4,5),(5,5),(5,6)]

第3条路径:[(0,0), (4,5),(5,5),(6,5)]

第4条路径:[(0,0), (1,0),(1,1),(4,5)]

第5条路径:[(0,0), (1,0),(1,1),(2,1)]

第6条路径:[(0,0), (1,0),(2,0),(2,1)]

第7条路径:[(0,0), (1,0),(2,0),(3,0)]

这里只解释第一条路径,其6条大家自己琢磨

step1:红色箭头 先删除Z: str1[0],,来到坐标(0,1)。这时候发现 A:str1[1]==str2[0] && B:str1[2]==str2[1] && C:str1[3]==str2[2] && D:str1[4]==str2[3],因此,坐标(0,1)走滑滑梯直接到了(4,5),

step2 第二步,黄色剪头,删除Z: str1[5], 来到坐标 (4,6),删除后发现E:str1[6]==str2[4],因此坐标(4,6)也坐滑滑梯来到坐标(5,7)。

step3 最后一步,蓝色箭头,插入F:str2[5],,来到坐标(6,7).

完成从str1,到str2的变化。一共用了3步操作(滑滑梯不算)。走的步数是小于 3*8=24步,因为有些线路的前期路径是公共的,一共走了13步(时间复杂度),实际在代码中只会走7步,还要减去6步,因为第一条路径达到终点时,循环已经结束了,其它6条最后一步不用走了,我们只要冠军。而最大公共字符串(字符列),编辑距离时间复杂度是6*7=42步。

6.3 代码部分

代码主要是三个部分,1、构建全部路径图;2、回溯出最优的路径;3、依靠路径找出两个序列间的关系。

代码只放部分,其余的感兴趣在评论区找我。

    def main(self):# 1、构造全路径图target_node = self._construct_graph()# 2、获取最优路径path_list = self._get_path(target_node)print(path_list)# 3、路径转化为关系all_relation = self._get_relation(path_list)print("====="*10)for relation in all_relation:print(relation)if __name__ == '__main__':s1 = "ZABCDZE"s2 = "ABCDEF"myers = Myers(s1, s2)myers.main()# [(0, 0), (4, 5), (5, 7), (6, 7)]
# ==================================================
# [('delete', 0), ('common', 1, 0), ('common', 2, 1), ('common', 3, 2), ('common', 4, 3)]
# [('delete', 5), ('common', 6, 4)]
# [('insert', 5)]

· 解释一下输出(print)

1、路径:[(0, 0), (4, 5), (5, 7), (6, 7)]

与Myers的路径图是一致的,与其中的最先到达终点的最优路径图是一致的。

2、关系:

[('delete', 0), ('common', 1, 0), ('common', 2, 1), ('common', 3, 2), ('common', 4, 3)]
        [('delete', 5), ('common', 6, 4)]
        [('insert', 5)]

一共三组关系,解释一下是什么意思

回顾目标,使得str1 = "ZABCDZE" ,通过约束规则变为str2="ABCDEF"

第一组:删除Z:str1[0],保留公共的A:str1[1]==str2[0] && B:str1[2]==str2[1] && C:str1[3]==str2[2] && D:str1[4]==str2[3],这时得到是 ABCD。

第二组;删除Z:str1[5], 保留公共的E:str1[6]==str2[4],得到 ABCDE

第三组;插入F:str2[5],得到 ABCDEF

3、得到这个关系后的作用,我们可以从这个关系得到最大公共字符串,最大公共子序列,以及编剧距离的值。

最大公共字符串:连续common的个数,直接数:4

最大公共序列,所有common的个数,直接数:5

编辑距离,每一组中,取插入和删除得最大值,然后相加: 1+1+1=3

一个速度比它三都快,结果完全可以转换成其中的任意的一个值。一个字评价:完美。

6.4 作用

它的作用在SVN,GIT的版本管理工具中的文本比对中会有用到。我们也可以利用word文档自动标记,来将两段相似的文本的不同之处,高亮显示。这是用 python-dcox的包生成的亮片对比文档,非手动标注!!!

我们随便找了一段代码,随便修改了几个字母,看看效果。

Myers效果展示

这样如果有人偷偷改了你的稿子,就一目了然了。

最大公共字符串,最大公共子序列,编辑距离,myers等算法相关推荐

  1. 穷举法求最大公共子序列C语言,算法--最长公共子序列(LongestCommon Subsequence, LCS)...

    定义: 两个字符串共有的最长的子序列(可不连续),最长公共字符串(Longest CommonSubstring)是两个字符串共有的最长的连续字符串. 方法:穷举法,动态规划 动态规划法的简介: &l ...

  2. python实现最大公共子序列

    介绍 子序列和子串的意思不一样,如下图所示,子序列不要求连续,只需要在给定序列中出现过,并且相对顺序一致.而子串需要连续. 图片来自动态规划 最长公共子序列 过程图解 最长公共子序列(LCS): 同时 ...

  3. 递归法:求两个串的最大公共子序列的长度

    问题:求两个串的最大公共子序列的长度 举例: 子串: abcgxs 与sabxfh 其最大公共子序列的为abx,长度为3 public class Zixulie {public static int ...

  4. buct oj 最大公共子序列问题

    问题 B 最大公共子序列问题 时间限制: 1 Sec  内存限制: 128 MB [提交] 题目描述 对序列X=(x1, x2, .., xm),定义其子序列为(xi1, xi2, .., xik), ...

  5. 最长公共子序列求序列模板提_最长公共子序列

    最长公共子序列求序列模板提 Description: 描述: This question has been featured in interview rounds of Amazon, MakeMy ...

  6. 北大OJ百练——4073:最长公共字符串后缀(C语言)

    刚刚看到一道北大的OJ题,很简单的一道题.原题如下(偷个懒,直接截图): 看完这道题,我想大家都和我一样觉得这道题很简单,事实也是如此,毕竟通过率很高. 我先来说一下我的思路吧.我是想先把这些所有的字 ...

  7. C++longest common string最长公共字符串的实现(附完整源码)

    C++longest common string最长公共字符串的实现 longest common string最长公共字符串实现的完整源码(定义,实现,main函数测试) longest commo ...

  8. 5922. 统计出现过一次的公共字符串

    5922. 统计出现过一次的公共字符串 给你两个字符串数组 words1 和 words2 ,请你返回在两个字符串数组中 都恰好出现一次 的字符串的数目. 示例 1:输入:words1 = [&quo ...

  9. DP-最大递增子序列与最大递增子数组; 最大公共子序列与最大公共子数组。

    这些都是动态规划的题目. 解决动态规划的题目有个重点就是找出递推方程. 但问题在于递归方程不是那么好找的.如何恰当的定义目标函数是最大的难点. 如最大公共子数组中可定义A[m][n]为以A[m] B[ ...

最新文章

  1. 家居建材企业信息化管理路在何方?
  2. 面码份量Java_JAVA语言(28道练习题)
  3. 正确理解和使用GBK及UTF-8编码
  4. foreach(表达式中的类型标识符) 内含语句
  5. GeoServer离线地图
  6. TCPDF微软雅黑字体
  7. Pillow图像处理
  8. SQL server 服务报 远程过程调用失败0x800706be
  9. 游戏制作中的大宝剑---常用的数据结构与算法
  10. 五分频电路(50%占空比)
  11. LintCode 644. 镜像数字 JavaScript算法
  12. tableFooterView中的按钮点击没反应
  13. 基本的SELECT语句的练习(MySQL)(SQLyog)
  14. 教你免费申请5T的微软OneDrive云盘
  15. jQuery的模糊匹配
  16. Java与C语言中的锁
  17. HTML中的Position定位的区别
  18. 教你设置微信小程序的服务通知推送!搜狗文章
  19. IBM投入千万美元支持中国渠道培训
  20. 【Vega Prime】000 - 初探Vega Prime

热门文章

  1. Flow Flip Fest正式启动| Flow极客马拉松正式开启,高额奖金等你来拿
  2. 匹兹堡大学申请条件计算机科学,匹兹堡大学工程学院计算机科学专业申请条件...
  3. 基于vue的开源管理系统模板
  4. 使用Tushare接口做中证500基差图
  5. 【ROS】—— ROS快速上手(一)
  6. 美妆个护市场真的相信“小鲜肉”吗?
  7. 1.8 正则表达式【匹配一个或多个字符】
  8. 乐鑫Esp32学习之旅⑦ esp32上利用GPIO中断做一个按键的短按和长按的回调事件,再也无须担心触发源。(附带Demo)
  9. 【数据库视频】报表服务
  10. 【干货】教你用python给你的微信朋友群发私人订制的藏头诗