最长公共子序列(LCS)是一类典型的动归问题。 
问题

给定两个序列(整数序列或者字符串)A和B,序列的子序列定义为从序列中按照索引单调增加的顺序取出若干个元素得到的新的序列,比如从序列A中取出 A[i1], A[i2], ...A[ik],其中0=< i1 <= i2 <= ... ik <= n-1得到的新的序列 A[i1].A[i2]....A[ik]即为A的一个子序列。 
    两个不同的原序列A和B可能有着相同的子序列,求出A和B的公共子序列的最长长度。

分析 
    这种“离散”性质,且有子结构的问题,考虑用动态规划来解决。定义“状态”: dp[i][j]表示 序列A的前缀 A[0....i]和序列B的前缀B[0....j]含有的最长公共子序列的长度。则有递推关系:

    dp[i][j] = dp[i-1][j-1] + 1; if (A[i] == B[j])
dp[i][j] = max{dp[i-1][j], dp[i][j-1]} if (a[i] != B[j])

对于递推关系的说明: 
    显然,若A[i] == B[j],A[0....i]和B[0...j]构成的最长公共子序列的长度为A[0...i-1]和B[0....j-1]的最长公共子序列的长度+1;如果A[i] != B[j],则可以证明 dp[i][j] >= dp[i-1][j], dp[i][j] >= dp[i][j-1]。这是因为 A[0...i]&&B[0....j]包含了A[0...i]&&B[0....j-1] 显然长度较长的两个子串的LCS要长于长度较短的两个子串的LCS。于是dp[i][j] >= max{dp[i-1][j], dp[i][j-1]}。 
    再说明 dp[i][j] <= max{dp[i][j-1], dp[i-1][j]}。 
    (1)首先,易证一个事实

  1. A[0....t1]&B[0...p1]的最长公共子串的长度len1 大于 A[0...t2]&B[0...p2]的最长公共子串的长度len2,如果t1 >= t2 且p1 >= p2

 
    (2)然后,如上图所示。假设dp[i][j-1] >= dp[i-1][j],若 dp[i][j] > dp[i][j-1],则B[j]肯定与A[t…i-1]中的某个数相同,其中t为A[0...i]和B[0...j-1]的公共子串的最后一个元素的位置。假设为A[k],那么,此时A[0...i-1]和B[0….j]的公共子串的的范围(A中是A[0….k],B中是B[0….j])要大于A[0...i]和B[0….j-1]公共子串的范围(A中是A[0…t],B中是B[0...j-1),于是dp[i-1][j] >= dp[i][j-1],与前提矛盾!

实现

memset(dp, 0, sizeof(dp));
dp[0][0] = (A[0] == B[0]);
if(A[1] == B[0] || A[0] == B[0])
dp[1][0] = 1;
if(B[1] == A[0] || B[0] == A[0])
dp[0][1] = 1;
for(int i = 1; i < n; i ++){
for(int j = 1; j < m; j ++){
if(A[i] == B[j])
dp[i][j] = dp[i-1][j-1] + 1;
else
dp[i][j] = max(dp[i][j-1], dp[i-1][j]);
}
}

最长公共子串 Longest Common Substring

它是最长公共子序列问题的一种特例,需要找出最长的公共的连续的一段字符构成的子串。状态dp[i][j] 表示 str1和str2中分别以 str1[i] 和 str2[j] 结尾的最长公共子串长度,它的递推公式为:

dp[i][j] = dp[i-1][j-1] + 1; 如果 str1[i] == str2[j]

dp[i][j] = 0; 如果 str1[i] != str2[j]

result = max(dp[i][j], result)

动态规划——最长公共子序列&&最长公共子串的更多相关文章

  1. 《算法导论》读书笔记之动态规划—最长公共子序列 & 最长公共子串(LCS)

    From:http://my.oschina.net/leejun2005/blog/117167 1.先科普下最长公共子序列 & 最长公共子串的区别: 找两个字符串的最长公共子串,这个子串要 ...

  2. 算法设计 - LCS 最长公共子序列&&最长公共子串 &&LIS 最长递增子序列

    出处 http://segmentfault.com/blog/exploring/ 本章讲解:1. LCS(最长公共子序列)O(n^2)的时间复杂度,O(n^2)的空间复杂度:2. 与之类似但不同的 ...

  3. 简单动态规划——最长公共子序列&&最长回文子序列&&最长上升||下降子序列

    最长公共子序列,顾名思义当然是求两个字符串的最长公共子序列啦,当然,这只是一道非常菜的动规,所以直接附上代码: #include<iostream> #include<cstdio& ...

  4. C语言 · 最长公共子序列 · 最长字符序列

    算法提高篇有两个此类题目: 算法提高 最长字符序列   时间限制:1.0s   内存限制:256.0MB      最长字符序列 问题描述 设x(i), y(i), z(i)表示单个字符,则X={x( ...

  5. LIS LCS 最长上升子序列 最长公共子序列 ...

    最长上升子序列,问题定义:http://blog.csdn.net/chenwenshi/article/details/6027086 代码: public static void getData( ...

  6. 最长公共子序列&最长公共子串

    首先区别最长公共子串和最长公共子序列  LCS(计算机科学算法:最长公共子序列)_百度百科 最长公共子串,这个子串要求在原字符串中是连续的.而最长公共子序列则并不要求连续. 最长公共子序列: http ...

  7. 二维动态规划&&二分查找的动态规划&&最长递增子序列&&最长连续递增子序列

    题目描述与背景介绍 背景题目: [674. 最长连续递增序列]https://leetcode-cn.com/problems/longest-continuous-increasing-subseq ...

  8. 最长上升子序列&&最长不下降子序列

    百练2757: 题目描述: 对于给定的序列,求出最长上升子序列的长度. 题目链接:http://bailian.openjudge.cn/practice/2757 解题思路 一.动态规划 1. 找子 ...

  9. ZZNU 1719(最长上升子序列+最长下降子序列)

    先吐血一发,噗! 再吐血一次,啊啊啊啊! 好吧,做了那么多次最长上升子序列,看这题看了半天才发现还有最长下降子序列,呵呵哒! AC代码: #include<stdio.h>//老恶心#in ...

随机推荐

  1. 如何在C++中调用C程序

    注意这里的C调用C++或者C++调用C意思是.c文件中调用.cpp文件中代码,或者相反. C++和C是两种完全不同的编译链接处理方式,如果直接在C++里面调用C函数,会找不到函数体,报链接错误. 要解 ...

  2. mysql分区 详解

    第18章:分区 目录 18.1. MySQL中的分区概述 18.2. 分区类型 18.2.1. RANGE分区 18.2.2. LIST分区 18.2.3. HASH分区 18.2.4. KEY分区 ...

  3. mybatis中sql语句传入多个参数方法

    1 使用map <select id="selectRole" parameterType="map" resultType="RoleMap& ...

  4. 简明 Vim 练级攻略(转,有些动态图不能显示,请看转载处)

    vim的学习曲线相当的大(参看各种文本编辑器的学习曲线),所以,如果你一开始看到的是一大堆VIM的命令分类,你一定会对这个编辑器失去兴趣的.下面的文章翻译自<Learn Vim Progress ...

  5. linux命令汇总1

    允许非root用户使用“sudo” root身份登录系统,执行“visudo”,根据示例添加新的一个规则(记住输入的密码是当前用户密码,而不是root密码)#不需要密码执行sudo命令hadoop   ...

  6. 聊一聊HTML <pre>标签

    聊一聊HTML <pre>标签 我们经常会在要保持文本格式的时候使用pre标签,比如当我们要展示源代码的时候,只要放一个pre标签,然后把源代码直接复制,粘贴,然后在页面上就可以保持好格式 ...

  7. 词法分析器总结--flex&bison

    转自:项目总结之词法分析器 无论是词法分析,还是语法分析,给我的第一感觉就是逻辑要严谨.由于项目有自己一套完整的语言和语法,设计好其对应的词法分析器和语法分析器显得尤为重要. 我们采用flex进行词法 ...

  8. R ggplot2 翻转坐标

    p <- ggplot(mpg, aes(class, hwy)) p + geom_boxplot() p + geom_boxplot() + coord_flip()

  9. java web hello world(二)基于Servlet理解监听

    java web最开始实现是通过Servlet实现,这里就来实现下,最原始的监听是如何实现的. 第一步,创建一个基本的web项目 ,参见(java web hello world(一)) 第二步,we ...

  10. linux 域和xenomai 实时域之间的交互

    /* * XDDP-based RT/NRT threads communication demo. * * Real-time Xenomai threads and regular Linux t ...