`
oywl2008
  • 浏览: 1003737 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

最长公共子序列(Longest Common Subsequence)

 
阅读更多

http://blog.csdn.net/hhygcy/article/details/3948969

 

 

这个问题也是算法导论上提过的问题。注意这个问题是Subsequence不是Substring。substring的话就是子串,子串的要求的连续相等的字符序列,而subsequence不要求连续。比如说ABCD和ABD。他们的longest common subsequence就是ABD。而Longest common substring就是AB。

这个问题和Edit Distance是同样的一类问题。解决这类的问题都是从一个优化的子结构开始得到递推式,从而给出一个一般的全局优化结构的过程。在这里,我们假定两个字符串分别是S1和S2。他们的长度是m和n。我们用M[i,j]来表示一个长度为i的S1和长度为j的S2的最优方案。我们要找的就是当M[m,n]是的方案。问题的关键就是要找到M[i,j]和之前的那些诸如M[1..i, 1..j]之间的关系。

我们把问题分成两种情况来讨论:

1. 如果S1[i] == S2[j]。就是i,j对应位置上的字符相等。那么可以得出M[i,j] = M[i-1,j-1]+1;为什么呢?可以想象的。如果M[i-1,j-1]也是一个最后方案,在这个最优方案上我们同时增加一个字符。而这两个字符又相等。那么我们只需要在这个M[i-1,j-1]的最优方案上++就可以了。

2. 如果S1[i] != S2[j]。那么就拿M[i-1,j]和M[i,j-1]来比较。M[i,j]的值就是M[i-1,j]和M[i,j-1]中大的值。这好比原来的字符串是S1[1...i-1]是ABC,S2[1...j-1]是ABE。那S1[1..i]是ABCE,S2[1..j]是ABEC。可以看出来这个时候M[i,j]不是由M[i-1,j-1]决定的,而是由ABCE和ABE或者ABC和ABEC来决定的,也就是M[i-1,j]和M[i,j-1]。

所以我们可以把这个问题的递归式写成:

recursive formula

 

 

 

在代码里面的d用来表示长度,也就是我们的M[i,j]数组,而b则用来回溯到这个S3。当然这里的流程也可以用这个图来说明:

flow

 

这个问题是动态规划中非常基础的一个问题,这个问题其实和另一个前面提到的问题很类似。就是Edit Distance的问题。Edit Distance问题又被成为Levenshtein distance问题。这里的问题描述的就是两个字符串经过若干次修改(添加字符,删除字符,替换字符)变为两个完全相等字符串。这里的distance就是指最少的修改次数。其实这个也就是《编程之美》中的那个字符串相似度的问题。

相似的,我们还是定义一个M[i,j]的二维模型。这时候一样还是分析M[i,j]的递归式。这里的结果还是比较相近的。

如果S1[i] == S2[j]。那么M[i,j]就等于M[i-1,j-1],就是说在S1[i]==S2[j]的情况下M[i,j]不会发生变化,显然不需要做什么改动。

如果S1[i] != S2[j]的时候,那么就是M[i-1,j-1],M[i-1,j]和M[i,j-1]来做比较,我们取最小的那个值+1就可以了。这里的M[i-1,j-1],M[i-1,j]和M[i,j-1]对应了添加删除替换这些操作。M[i-1,j-1]可以替换最后一个S1[i]和S[j]来完成,而M[i-1,j]可以通过添加S1[i]来完成匹配。

这里我也把C++的代码贴出来参考一下:

 

[cpp] view plain copy
 
  1. // Edit_Distance.cpp : Defines the entry point for the console application.  
  2. //  
  3. #include "stdafx.h"  
  4. #include <vector>  
  5. #include <iostream>  
  6. #include <algorithm>  
  7. #include "windows.h"  
  8. template <class T> unsigned int edit_distance(const T& s1, const T& s2)  
  9. {  
  10.     const size_t len1 = s1.size(), len2 = s2.size();  
  11.     std::vector<std::vector<unsigned int> > d(len1 + 1, std::vector<unsigned int>(len2 + 1));  
  12.     for(int i = 1; i <= len1; ++i) d[i][0] = i;  
  13.     for(int i = 1; i <= len2; ++i) d[0][i] = i;  
  14.     for(int i = 1; i <= len1; ++i)  
  15.         for(int j = 1; j <= len2; ++j)  
  16.             d[i][j] = std::min<> ( std::min<> (d[i - 1][j] + 1,d[i][j - 1] + 1), d[i - 1][j - 1] + (s1[i - 1] == s2[j - 1] ? 0 : 1) );  
  17.     return d[len1][len2];  
  18. }  
  19.   
  20. int _tmain(int argc, _TCHAR* argv[])  
  21. {  
  22.     std::string s1("ABCBDAB");  
  23.     std::string s2("BDCABA");  
  24.     std::cout << "edit distance = " << edit_distance(s1, s2) << std::endl;;  
  25.     system("pause");  
  26.     return 0;  
  27. }  

 

想来这大概也是《编程之美》中提到的非递归的办法吧。时间复杂度和空间复杂度都是O(mn)。需要额外说明的一点是,尽管这两个问题比较类似,但是好像还不能直接简单的由一个问题推导出另一个问题。我原来有想法希望这两个问题可以互相推导是不正确的。

分享到:
评论

相关推荐

    最长公共子序列Longest Common Subsequence - Super Jiju的小窝_ To be with my Dearest Jessie

    最长公共子序列Longest Common Subsequence - Super Jiju的小窝_ To be with my Dearest Jessie

    最长公共子序列问题.docx

    最长公共子序列(Longest Common Subsequence,LCS)问题是一个经典的动态规划问题,通常用于比较两个序列的相似程度。给定两个序列,找出它们之间的最长公共子序列的长度。 下面是一个 Python 的动态规划实现: `...

    什么是最长公共子序列问题

    最长公共子序列(Longest Common Subsequence, LCS)问题是一个经典的计算机科学和生物信息学问题。给定两个序列,我们需要找到它们的最长公共子序列。一个序列的子序列是通过删除一些(也可以不删除)元素但不改变...

    最长公共子序列的Nakatsu算法

    最长公共子序列的Nakatsu算法 最长公共子序列(Longest Common Subsequence,LCS)是将两个给定字符串分别删去零个或多个字符后得到的长度最长的相同字符序列。

    最长公共子序列问题.zip

    最长公共子序列(Longest Common Subsequence, LCS)问题是计算机科学和生物信息学中的一个经典问题。它要求找出两个序列(如字符串、列表或数组)的最长公共子序列,即在两个序列中以相同顺序出现,并且不改变原有...

    最长公共子序列问题.md

    最长公共子序列问题(Longest Common Subsequence,LCS)是计算机科学和生物信息学中的一个经典问题。这个问题是寻找两个(或多个)给定序列的最长子序列,这个子序列在两个序列中都以相同的相对顺序出现。子序列...

    javascript实现最长公共子序列实例代码

    最长公共子序列(Longest Common Subsequence LCS)是从给定的两个序列X和Y中取出尽可能多的一部分字符,按照它们在原序列排列的先后次序排列得到。LCS问题的算法用途广泛,如在软件不同版本的管理中,用LCS算法找到...

    利用C++实现最长公共子序列与最长公共子串

    最长公共子序列(Longest Common Subsequence, LCS),顾名思义,是指在所有的子序列中最长的那一个。子串是要求更严格的一种子序列,要求在母串中连续地出现。在上述例子的中,最长公共子序列为blog(cnblogs, ...

    C语言求解最长公共子字符串问题及相关的算法分析

    题目:如果字符串一的所有字符按其在字符串...分析:求最长公共子序列(Longest Common Subsequence, LCS)是一道非常经典的动态规划题,因此一些重视算法的公司像MicroStrategy都把它当作面试题。 完整介绍动态规划将

    最长公共子序列的泛型算法

    经典的公共子序列算法需要两个序列的长度已知.而且通常用于计算字符串的公共子序列. 我实现的算法剥离了一些易变部分,使得算法极度可适配.能用于字符串公共子序列计算和文件diff计算.理论上能用于任何具备相似特征的...

    longest-common-subsequence.py

    最长公共子序列问题,动态规划法

    Longest-Common-Subsequence:这是一个实施动态编程以查找最长公共子序列的项目

    最长公共子序列 这是一个实施动态编程以查找最长公共子序列的项目,该项目已作为ITCS-6114 / 8114:算法和数据结构课程的一部分进行。 程序和数据结构设计:给定的项目被编写为3个单独的程序。 这些程序是用Java...

    LCS.rar_连续子序列

    最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知...

    利用C语言来求最大连续子序列乘积的方法

    也就是说:最长公共子串(Longest CommonSubstring)和最长公共子序列(LongestCommon Subsequence,LCS)的区别:  子串(Substring)是串的一个连续的部分,子序列(Subsequence)则是从不改变序列的

    实验九lcs算法.doc

    最长公共子序列(Longest Common Subsequence LCS)是从给定的两个序列X和Y中取出尽可能多的一部分字符,按照它们在原序列排列的先后次序排列得到。

    深入解析最长公共子串

    题目:如果字符串一的所有字符... 分析:求最长公共子串(Longest Common Subsequence, LCS)是一道非常经典的动态规划题,因此一些重视算法的公司像MicroStrategy都把它当作面试题。完整介绍动态规划将需要很长的篇幅

    leetcode338-interview-bit:面试位问题的解决方案回购

    最长公共子序列 中等的 2921 38添加到列表分享 给定两个字符串text1和text2 ,返回它们最长公共子序列的长度。 如果没有公共子序列,则返回0 。 字符串的亚序列是从原来的字符串与一些字符产生一个新的字符串(可以...

    lcs-parallel:最长公共子序列并行实现

    ##Longest Common Subsequence Parallelization with MPI, OpenMP, PThreads ###Design 每个线程/进程将处理 F 表的一列,并根据 DP 公式进行计算。 代码中略有变化,因为这里每个线程将负责一行,因为此矩阵加载到...

    leetcode刷题app-blog:问题博客

    leetcode刷题app 面试 Google ...最长公共子序列 - LCS(Longest Common Subsequence) 2.2 最长递增子序列 - LIS(Longest Increasing Subsequence) 2.3 01背包 - 01 Knapsack 3. 数据结构 3.1 二叉搜索树

    leetcode中国-code_algo:编码,编码,编码

    leetcode中国 code_algo :可行但是计算的时间复杂度高(O(2^n)) :将计算的结果放入缓存的备忘录中,如果下次计算再次用...最长公共子序列(Longest Common Subsequence,简称 LCS)是一道非常经典的面试题目, 因为它的

Global site tag (gtag.js) - Google Analytics