前言

这篇是大三算法分析与设计课程的第一篇博客,写他是因为上课学到了,并且也算是留作记忆,以后学习时方便使用。

这篇博客主要想讲讲动态规划法,然后以LCS问题为例展开来说一下怎么利用动态规划法求解它,下面是自己的一些理解和总结,有不对的地方还请大家指正。

动态规划法

动态规划法(dynamic programming)通常用于求解最优化问题(optimization problem),它适用于那些子问题相互重叠的情况,即子问题不独立,不同的子问题具有公共的子子问题(就是子问题的子问题)。这显然与分治法是不同的,分治法将问题划分为不重叠的子问题,然后分别求解这些子问题,最后将这些问题合并得到最终的解。

对于具有公共子问题的情况,分治法会做很多不必要的工作,它会多次求解同一子子问题。动态规划法却不一样,对每个子子问题它只会求解一次,将其保存在一个表格中,避免了不必要的重复计算。

如之前所说,动态规划法用于求解最优化问题,这就意味着可能这个问题,有很多解,但是呢,不一定都是最优解。利用动态规划法求出来的是这个问题的一个最优解(an optimal solution),记住这里求解的只是最优解(the optimal solution)中的一个,因为最优解可能有多个。

设计一个问题的动态规划算法主要有一下的几步

(1)       找出最优解的性质,刻画其结构特征;

(2)       递归的定义最优解的值;

(3)       以自底向上的方式计算出最优值;

(4)       根据计算最优解时得到的信息,构造一个最优解。

如果你只需要一个最优解的值,而不是这个结本身,就不需要第(4)步。如果你需要得到这个解本身,也就是说你需要执行第(4)步,这往往需要我们在第(3)步中记录一些额外的信息,以方便第(4)步的求解。

下面让我们来看看LCS问题如何利用动态规划法求解。

最长公共子序列的动态规划法实现
最长公共子序列(longest-common-subsequence, LCS)
     (1)子序列:一个序列X = x1x2...xn,中任意删除若干项,剩余的序列叫做A的一个子序列。也可以认为是从序列A按原顺序保留任意若干项得到的序列。
      例如:对序列 1,3,5,4,2,6,8,7来说,序列3,4,8,7 是它的一个子序列。对于一个长度为n的序列,它一共有2^n 个子序列,有(2^n – 1)个非空子序列。在这里需要提醒大家,子序列不是子集,它和原始序列的元素顺序是相关的。

(2)公共子序列:如果序列Z既是序列X的子序列,同时也是序列Y的子序列,则称它为序列X和序列Y的公共子序列。空序列是任何两个序列的公共子序列。

(3)最长公共子序列:X和Y的公共子序列中长度最长的(包含元素最多的)叫做X和Y的最长公共子序列。

这个问题如果用穷举法时间,最终求出最长公共子序列时,时间复杂度是Ο(2mn),是指数级别的复杂度,对于长序列是不适用的。因此我们使用动态规划法来求解。

刻画最长公共子序列问题的最优子结构
      设X=x1x2…xm和Y=y1y2…yn是两个序列,Z=z1z2…zk是这两个序列的一个最长公共子序列。

1.      如果xm=yn,那么zk=xm=yn,且Zk-1是Xm-1,Yn-1的一个最长公共子序列;

2.      如果xm≠yn,那么zk≠xm,意味着Z是Xm-1,Y的一个最长公共子序列;

3.      如果xm≠yn,那么zk≠yn,意味着Z是X,Yn-1的一个最长公共子序列。

从上面三种情况可以看出,两个序列的LCS包含两个序列的前缀的LCS。因此,LCS问题具有最优子结构特征。

递归的定义最优值
      从最优子结构可以看出,如果xm=yn,那么我们应该求解Xm-1,Yn-1的一个LCS,并且将xm=yn加入到这个LCS的末尾,这样得到的一个新的LCS就是所求。

如果xm≠yn,我们需要求解两个子问题,分别求Xm-1,Y的一个LCS和X,Yn-1的一个LCS。两个LCS中较长者就是X和Y的一个LCS。

可以看出LCS问题具有重叠子问题性质。为了求X和Y的一个LCS,我们需要分别求出Xm-1,Y的一个LCS和X,Yn-1的一个LCS,这几个字问题又包含了求出Xm-1,Yn-1的一个LCS的子子问题。(有点绕了。。。晕没晕。。。。)

根据上面的分析,我们可以得出下面的公式;

计算最优解的值
       根据上面的,我们很容易就可以写出递归计算LCS问题的程序,通过这个程序我们可以求出各个子问题的LCS的值,此外,为了求解最优解本身,我们好需要一个表b,b[i,j]记录使C[i,j]取值的最优子结构。

完整题目代码如下

// 最长公共子序列问题
//QQ/WeChat:23540008#include "stdlib.h"
#include <iostream>
using namespace std; const int M = 7;
const int N = 6;void output(char *s,int n);
void LCSLength(int m,int n,char *x,char *y,int **c);
void LCS(int i,int j,char *x,int **c);int main()
{//X={A,B,C,B,D,A,B}//Y={B,D,C,A,B,A}char x[] = {' ','A','B','C','B','D','A','B'};char y[] = {' ','B','D','C','A','B','A'};int **c = new int *[M+1];for(int i=0;i<=M;i++)  {  c[i] = new int[N+1];} cout<<"序列X:"<<endl;output(x,M);cout<<"序列Y:"<<endl;output(y,N);LCSLength(M,N,x,y,c);cout<<"序列X、Y最长公共子序列长度为:"<<c[M][N]<<endl;cout<<"序列X、Y最长公共子序列为:"<<endl;LCS(M,N,x,c);cout<<endl;
}void output(char *s,int n)
{for(int i=1; i<=n; i++){cout<<s[i]<<" ";}cout<<endl;
}void LCSLength(int m,int n,char *x,char *y,int **c)
{int i,j;for(i=1; i<=m; i++)c[i][0] = 0;for(i=1; i<=n; i++)c[0][i] = 0;for(i=1; i<=m; i++){for(j=1; j<=n; j++){if(x[i]==y[j]){c[i][j]=c[i-1][j-1]+1;}else if(c[i-1][j]>=c[i][j-1]){c[i][j]=c[i-1][j];}else{c[i][j]=c[i][j-1];}}}
}void LCS(int i,int j,char *x,int **c)
{if(i==0 || j==0){return;}if(c[i][j]==c[i-1][j-1]+1){LCS(i-1,j-1,x,c);cout<<x[i]<<" ";}else if(c[i-1][j]>=c[i][j-1]){LCS(i-1,j,x,c);}else{LCS(i,j-1,x,c);}
}

【算法】动态规划法——最长公共子序列(LCS)相关推荐

  1. 动态规划算法解最长公共子序列LCS问题

    动态规划算法解LCS问题 作者 July 二零一零年十二月三十一日 本文参考:微软面试100题系列V0.1版第19.56题.算法导论.维基百科. 第一部分.什么是动态规划算法 ok,咱们先来了解下什么 ...

  2. 算法之最长公共子序列(LCS)问题

    算法课上老师留的作业,最长公共子序列LCS(Longest Common Subsequence)问题,首先看到这个问题感觉有点复杂,和最长公共子串不同,公共子序列并不要求元素相邻,看起来只有穷举才能 ...

  3. 算法导论-----最长公共子序列LCS(动态规划)

    目录 一.概念梳理 二.最长公共子序列解决方案 方案1:蛮力搜索策略 方案2:动态规划策略 三.C代码实现 实现1 实现2(空间优化) 一.概念梳理   1. 子序列(subsequence): 一个 ...

  4. LCS算法:最长公共子序列

    LCS算法:最长公共子序列定义: 一个序列A任意删除若干个字符得到新序列B,则A叫做B的子序列 两个序列X和Y的公共子序列中,长度最长的那个,定义为X和Y的最长公共子序列 例如: X={A,B,C,B ...

  5. 算法学习 - 最长公共子序列(LCS)C++实现

    最长公共子序列 最长公共子序列的问题很简单,就是在两个字符串中找到最长的子序列,这里明确两个含义: 子串:表示连续的一串字符 . 子序列:表示不连续的一串字符. 所以这里要查找的是不连续的最长子序列, ...

  6. java lcs_Java算法之最长公共子序列问题(LCS)实例分析

    本文实例讲述了Java算法之最长公共子序列问题(LCS).分享给大家供大家参考,具体如下: 问题描述:一个给定序列的子序列是在该序列中删去若干元素后得到的序列.确切地说,若给定序列X= { x1, x ...

  7. LCS算法(最长公共子序列问题)

    1.问题 注意:LCS问题即公共子序列问题,不要求所求得的字符在所给的字符串中是连续的(例如:输入两个字符串ABCD和BAC,字符串AC和BC都是它们的最长公共子序列,长度为2.输入两个字符串ABCB ...

  8. 程序员编程艺术第十一章:最长公共子序列(LCS)问题

    程序员编程艺术第十一章:最长公共子序列(LCS)问题 0.前言 程序员编程艺术系列重新开始创作了(前十章,请参考程序员编程艺术第一~十章集锦与总结).回顾之前的前十章,有些代码是值得商榷的,因当时的代 ...

  9. 相似度:最长公共子序列--LCS

    一.概念 1.子序列 一个特定序列的子序列就是将给定序列中零个或多个元素去掉后得到的结果(不改变元素间相对次序).如序列[A,B,C,B,D,A,B]的子序列有:[A,B],[B,C,A],[A,D, ...

  10. 动态规划之最长公共子序列(LCS)

    最长公共子序列(LCS,Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最 ...

最新文章

  1. 低版本火狐提示HTTPS链接不安全的解决办法
  2. rawquery 没扎到返回什么_当mysql_query返回false时
  3. APK加壳【1】初步方案实现详解
  4. What Are You Talking About
  5. python医疗系统代码_吴裕雄 人工智能 java、javascript、HTML5、python、oracle ——智能医疗系统WEB端复诊代码简洁版实现...
  6. 在java.library.path中找不到允许在生产环境中实现最佳性能的基于APR的Apache Tom.....
  7. 详解Java中static关键字和final关键字的功能
  8. [.Net 4.0]泛型的协变,以及高阶函数对泛型的影响 Part 1
  9. 用于指纹验证的C#框架
  10. HTML的form表单标签
  11. Linux的学习之路grep命令
  12. Android视频的操作
  13. 判断单双周java_单双周计算
  14. java debug命令_Mame DEBUG调试命令详细指令速查大全
  15. 易宝支付 CTO 陈斌:如何做一个好的 CTO
  16. 全国失信被执行人黑名单信息查询API接口
  17. 如何区分加密、压缩、编码?
  18. 百度地图缩放级别与比例尺的关系
  19. C++图像处理OpenCV之屠龙宝刀第11篇 —— opencv_contrib(OpenCV贡献库)
  20. 外国人坐地铁到底玩不玩手机?

热门文章

  1. lopatkin俄大神精简中文系统Windows 10 Enterprise 18362.116 19H1 Release x86-x64 ZH-CN DREY
  2. AI实践之路:决策树
  3. 如何使用Arduino开发板和DS1307 RTC模块制作智能提醒器
  4. 软件赋能智造——第五届“设计+运维”国产工业软件研讨会圆满召开
  5. Python Web中REST API使用示例——基于云平台+云服务打造自己的在线翻译工具
  6. 2010年最抢手的热门职业
  7. ANSYS Workbench中的网格优化方法
  8. word从任意页插入页码
  9. 51单片机读取DS18B20温度传感器
  10. 冒险岛2官网模拟之三单击登录弹出登陆框的具体实现(连载)