最大公共字符串,最大公共子序列,编辑距离,myers等算法
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的方法,走快车道。
6.2 举例说明Myers路径
以str1 = "ZABCDZE" , str2="ABCDEF"为例,说明路径方式
先来说一个目标,将str1通过约束的规则变为str2,但是要求操作次数最小,规则如下:
只能有2种操作,1、删除 str1的某个字符;2、插入str2某个字符。或者保留二者相同的字符。且每个字符串中的每个字符无论是删除,插入,还是保留相同(滑滑梯操作),皆只能使用一次。而 操作次数=删除次数 + 插入次数。在图中,横向代表删除str1中的某个字符,纵向路径代表插入str2中某字符,而斜线代表保留相同的某字符。
红色箭头代表第一步,黄色箭头代表第二步,蓝色箭头代表第三步,所有的路径操作次数都是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等算法相关推荐
- 穷举法求最大公共子序列C语言,算法--最长公共子序列(LongestCommon Subsequence, LCS)...
定义: 两个字符串共有的最长的子序列(可不连续),最长公共字符串(Longest CommonSubstring)是两个字符串共有的最长的连续字符串. 方法:穷举法,动态规划 动态规划法的简介: &l ...
- python实现最大公共子序列
介绍 子序列和子串的意思不一样,如下图所示,子序列不要求连续,只需要在给定序列中出现过,并且相对顺序一致.而子串需要连续. 图片来自动态规划 最长公共子序列 过程图解 最长公共子序列(LCS): 同时 ...
- 递归法:求两个串的最大公共子序列的长度
问题:求两个串的最大公共子序列的长度 举例: 子串: abcgxs 与sabxfh 其最大公共子序列的为abx,长度为3 public class Zixulie {public static int ...
- buct oj 最大公共子序列问题
问题 B 最大公共子序列问题 时间限制: 1 Sec 内存限制: 128 MB [提交] 题目描述 对序列X=(x1, x2, .., xm),定义其子序列为(xi1, xi2, .., xik), ...
- 最长公共子序列求序列模板提_最长公共子序列
最长公共子序列求序列模板提 Description: 描述: This question has been featured in interview rounds of Amazon, MakeMy ...
- 北大OJ百练——4073:最长公共字符串后缀(C语言)
刚刚看到一道北大的OJ题,很简单的一道题.原题如下(偷个懒,直接截图): 看完这道题,我想大家都和我一样觉得这道题很简单,事实也是如此,毕竟通过率很高. 我先来说一下我的思路吧.我是想先把这些所有的字 ...
- C++longest common string最长公共字符串的实现(附完整源码)
C++longest common string最长公共字符串的实现 longest common string最长公共字符串实现的完整源码(定义,实现,main函数测试) longest commo ...
- 5922. 统计出现过一次的公共字符串
5922. 统计出现过一次的公共字符串 给你两个字符串数组 words1 和 words2 ,请你返回在两个字符串数组中 都恰好出现一次 的字符串的数目. 示例 1:输入:words1 = [&quo ...
- DP-最大递增子序列与最大递增子数组; 最大公共子序列与最大公共子数组。
这些都是动态规划的题目. 解决动态规划的题目有个重点就是找出递推方程. 但问题在于递归方程不是那么好找的.如何恰当的定义目标函数是最大的难点. 如最大公共子数组中可定义A[m][n]为以A[m] B[ ...
最新文章
- 家居建材企业信息化管理路在何方?
- 面码份量Java_JAVA语言(28道练习题)
- 正确理解和使用GBK及UTF-8编码
- foreach(表达式中的类型标识符) 内含语句
- GeoServer离线地图
- TCPDF微软雅黑字体
- Pillow图像处理
- SQL server 服务报 远程过程调用失败0x800706be
- 游戏制作中的大宝剑---常用的数据结构与算法
- 五分频电路(50%占空比)
- LintCode 644. 镜像数字 JavaScript算法
- tableFooterView中的按钮点击没反应
- 基本的SELECT语句的练习(MySQL)(SQLyog)
- 教你免费申请5T的微软OneDrive云盘
- jQuery的模糊匹配
- Java与C语言中的锁
- HTML中的Position定位的区别
- 教你设置微信小程序的服务通知推送!搜狗文章
- IBM投入千万美元支持中国渠道培训
- 【Vega Prime】000 - 初探Vega Prime
热门文章
- Flow Flip Fest正式启动| Flow极客马拉松正式开启,高额奖金等你来拿
- 匹兹堡大学申请条件计算机科学,匹兹堡大学工程学院计算机科学专业申请条件...
- 基于vue的开源管理系统模板
- 使用Tushare接口做中证500基差图
- 【ROS】—— ROS快速上手(一)
- 美妆个护市场真的相信“小鲜肉”吗?
- 1.8 正则表达式【匹配一个或多个字符】
- 乐鑫Esp32学习之旅⑦ esp32上利用GPIO中断做一个按键的短按和长按的回调事件,再也无须担心触发源。(附带Demo)
- 【数据库视频】报表服务
- 【干货】教你用python给你的微信朋友群发私人订制的藏头诗