Python求两个字符串最长公共子序列代码实例


Posted in Python onMarch 05, 2020

一、问题描述

给定两个字符串,求解这两个字符串的最长公共子序列(Longest Common Sequence)。比如字符串1:BDCABA;字符串2:ABCBDAB。则这两个字符串的最长公共子序列长度为4,最长公共子序列是:BCBA

二、算法求解

这是一个动态规划的题目。对于可用动态规划求解的问题,一般有两个特征:①最优子结构;②重叠子问题

①最优子结构

设X=(x1,x2,...,xn)和Y=(y1,y2,...,ym)是两个序列,将X和Y的最长公共子序列记为LCS(X,Y)

找出LCS(X,Y)就是一个最优化问题。因为,我们需要找到X和Y中最长的那个公共子序列。而要找X和Y的LCS,首先考虑X的最后一个元素和Y的最后一个元素。

⑴如果xn=ym,即X的最后一个元素与Y的最后一个元素相同,这说明该元素一定位于公共子序列中。因此,现在只需要找:LCS(Xn-1,Ym-1)

LCS(Xn-1,Ym-1)就是原问题的一个子问题。为什么叫子问题?因为它的规模比原问题小。

为什么是最优的子问题?因为我们要找的是Xn-1和Ym-1的最长公共子序列啊。最长的!换句话说就是最优的那个。

⑵如果xn!=ym,这下要麻烦一点,因为它产生了两个子问题:LCS(Xn-1,Ym)和LCS(Xn,Ym-1)

因为序列X和序列Y的最后一个元素不相等,那说明最后一个元素不可能是最长公共子序列中的元素。

LCS(Xn-1,Ym)表示:最长公共序列可以在(x1,x2,...xn-1)和(y1,y2,...,ym)中找。

LCS(Xn,Ym-1)表示:最长公共序列可以在(x1,x2,...xn)和(y1,y2,...,ym-1)中找。

求解上面两个子问题,得到的公共子序列谁最长,那谁就是LCS(X,Y)。用数学表示就是:

LCS=max{LCS(Xn-1,Ym),LCS(Xn,Ym-1)}

由于条件⑴和⑵考虑到了所有可能的情况。因此,我们成功的把原问题转化成了三个规模更小的问题。

②重叠子问题

重叠子问题是什么?就是说原问题转化成子问题后,子问题中有相同的问题。

原问题是:LCS(X,Y)。子问题有❶LCS(Xn-1,Ym-1)❷ LCS(Xn-1,Ym)❸ LCS(Xn,Ym-1)

乍一看,这三个问题是不重叠的。可本质上它们是重叠的,因为它们只重叠了一大部分。举例:

第二个子问题:LCS(Xn-1,Ym)就包含了问题❶LCS(Xn-1,Ym-1),为什么?

因为,当Xn-1和Ym的最后一个元素不相同时,我们又需要将LCS(Xn-1,Ym-1)进行分解:分解成:LCS(Xn-1,Ym-1)和LCS(Xn-2,Ym)

也就是说:在子问题的继续分解中,有些问题是重叠的。

由于像LCS这样的问题,它具有重叠子问题的性质,因此:用递归来求解就太不划算了。国为采用递归,它重复地求解了子问题,而且需要注意的是,所有子问题加起来的个数是指数级的。

那么问题来了,如果用递归求解,有指数级个子问题,故时间复杂度是指数级的。这指数级个子问题,难道用了动态规划,就变成多项式时间了??

关键是采用动态规划时,并不需要去一一计算那些重叠了的子问题。或者说:用了动态规划之后,有些子问题是通过“查表”直接得到的,而不是重新又计算一遍得到的。举个例子:比如求Fib数列。

Python求两个字符串最长公共子序列代码实例

求fib(5),分解成了两个子问题:fib(4)和fib(3),求解fib(4)和fib(3)时,又分解了一系列的小问题...

从图中可以看出:根的左右子树:fib(4)和fib(3)下,是有很多重叠的!比如,对于fib(2),它就一共出现了三次。如果用递归来求解,fib(2)就会被计算三次,而用DP(Dynamic Programming)动态规划,则fib(2)只会计算一次,其他两次则是通过“查表”直接求得。而且,更关键的是:查找求得该问题的解之后,就不需要再继续去分解该问题了。而对于递归,是不断地将问题解,直到分解为基准问题(fib(0)或者fib(1))

说了这么多,还是写下最长公共子序列的递归式才完整。

Python求两个字符串最长公共子序列代码实例

C[i,j]表示:(x1,x2,...,xi)和(y1,y2,...,yj)的最长公共子序列的长度。公式的具体解释可参考《算法导论》动态规划章节

三、LCS Python代码实现

#! /usr/bin/env python3
# -*- coding:utf-8 -*-

# Author  : mayi
# Blog   : http://www.cnblogs.com/mayi0312/
# Date   : 2019/5/16
# Name   : test03
# Software : PyCharm
# Note   : 用于实现求解两个字符串的最长公共子序列


def longestCommonSequence(str_one, str_two, case_sensitive=True):
  """
  str_one 和 str_two 的最长公共子序列
  :param str_one: 字符串1
  :param str_two: 字符串2(正确结果)
  :param case_sensitive: 比较时是否区分大小写,默认区分大小写
  :return: 最长公共子序列的长度
  """
  len_str1 = len(str_one)
  len_str2 = len(str_two)
  # 定义一个列表来保存最长公共子序列的长度,并初始化
  record = [[0 for i in range(len_str2 + 1)] for j in range(len_str1 + 1)]
  for i in range(len_str1):
    for j in range(len_str2):
      if str_one[i] == str_two[j]:
        record[i + 1][j + 1] = record[i][j] + 1
      elif record[i + 1][j] > record[i][j + 1]:
        record[i + 1][j + 1] = record[i + 1][j]
      else:
        record[i + 1][j + 1] = record[i][j + 1]

  return record[-1][-1]

if __name__ == '__main__':
  # 字符串1
  s1 = "BDCABA"
  # 字符串2
  s2 = "ABCBDAB"
  # 计算最长公共子序列的长度
  res = longestCommonSequence(s1, s2)
  # 打印结果
  print(res) # 4

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python常见文件操作的函数示例代码
Nov 15 Python
Python使用MySQLdb for Python操作数据库教程
Oct 11 Python
Python 自动补全(vim)
Nov 30 Python
python 实现红包随机生成算法的简单实例
Jan 04 Python
Python之读取TXT文件的方法小结
Apr 27 Python
Python 把序列转换为元组的函数tuple方法
Jun 27 Python
python networkx 包绘制复杂网络关系图的实现
Jul 10 Python
Flask框架中request、请求钩子、上下文用法分析
Jul 23 Python
python list的index()和find()的实现
Nov 16 Python
详解pandas映射与数据转换
Jan 22 Python
Python实现随机生成迷宫并自动寻路
Jun 13 Python
python库Tsmoothie模块数据平滑化异常点抓取
Jun 10 Python
Python操作MongoDb数据库流程详解
Mar 05 #Python
Python文字截图识别OCR工具实例解析
Mar 05 #Python
win10下opencv-python特定版本手动安装与pip自动安装教程
Mar 05 #Python
python+OpenCV实现图像拼接
Mar 05 #Python
windows下Pycharm安装opencv的多种方法
Mar 05 #Python
解决pycharm中opencv-python导入cv2后无法自动补全的问题(不用作任何文件上的修改)
Mar 05 #Python
浅谈Python的方法解析顺序(MRO)
Mar 05 #Python
You might like
PHP常用代码大全(新手入门必备)
2010/06/29 PHP
PHP上传图片进行等比缩放可增加水印功能
2014/01/13 PHP
教你如何用php实现LOL数据远程获取
2014/06/10 PHP
详解YII关联查询
2016/01/10 PHP
laravel 解决强制跳转 https的问题
2019/10/22 PHP
javascript基于jQuery的表格悬停变色/恢复,表格点击变色/恢复,点击行选Checkbox
2008/08/05 Javascript
jQuery Ajax之load()方法
2009/10/12 Javascript
jquery validate.js表单验证的基本用法入门
2010/05/13 Javascript
jQuery页面滚动浮动层智能定位实例代码
2011/08/23 Javascript
Js 回车换行处理的办法及replace方法应用
2013/01/24 Javascript
如何使用json在前后台进行数据传输实例介绍
2013/04/11 Javascript
开发插件的两个方法jquery.fn.extend与jquery.extend
2013/11/21 Javascript
javascript正则表达式定义(语法)总结
2016/01/08 Javascript
js浏览器滚动条卷去的高度scrolltop(实例讲解)
2017/07/07 Javascript
详解Vue中的基本语法和常用指令
2019/07/23 Javascript
详解elementui之el-image-viewer(图片查看器)
2019/08/30 Javascript
ckeditor一键排版功能实现方法分析
2020/02/06 Javascript
Vue双向绑定实现原理与方法详解
2020/05/07 Javascript
详解vue 组件
2020/06/11 Javascript
[01:06:18]DOTA2-DPC中国联赛 正赛 Phoenix vs Dynasty BO3 第二场 1月26日
2021/03/11 DOTA
python3中bytes和string之间的互相转换
2017/02/09 Python
解决PyCharm控制台输出乱码的问题
2019/01/16 Python
Python实现操纵控制windows注册表的方法分析
2019/05/24 Python
python 写函数在一定条件下需要调用自身时的写法说明
2020/06/01 Python
HTML5之SVG 2D入门4—笔画与填充
2013/01/30 HTML / CSS
SEPHORA新西兰官方网站:购买化妆品和护肤品
2016/12/02 全球购物
严选全球尖货,立足香港:Bonpont宝盆
2018/07/24 全球购物
Paradox London官方网站:英国新娘鞋婚礼鞋品牌
2019/08/29 全球购物
android面试问题与答案
2016/12/27 面试题
夜大毕业自我鉴定
2013/10/11 职场文书
区优秀教师事迹材料
2014/02/10 职场文书
《要下雨了》教学反思
2014/02/17 职场文书
应用心理学专业求职信
2014/08/04 职场文书
中学总务处工作总结
2015/08/12 职场文书
Nest.js参数校验和自定义返回数据格式详解
2021/03/29 Javascript
SpringBoot项目多数据源及mybatis 驼峰失效的问题解决方法
2022/07/07 Java/Android