最直白方法:时间复杂度是O(n3), 空间复杂度是常数

reference:http://blog.csdn.net/monkeyandy/article/details/7957263

/**

** copyright@andy

** http://blog.csdn.net/MonkeyAndy

**/

首先介绍动态规划方法的相关知识

动态规划方法的基本思想:

分成若干个子问题,先求解子问题,然后根据子问题的解求得原问题的解。经分解得到的子问题往往不是互相独立的。可重复利用!

其核心思想就是分治,分治方法的特点是分解后的子问题相对独立,可以通过简单的合并算法得到原问题的解!

动态规划方法的应用对象:
优化问题:

  1. 一个优化问题可能有很多可行解,每个解都有一个求解代价,
  2. 我们希望选择一个具有最少代价的解。
  3. 一个优化问题可能有多个优化解。

动态规划方法:
当一个优化问题可分为多个子问题,子问题的解在构造上一级问题的求解过程中被重复使用。 这样可以节省计算时间与空间。

动态规划算法的步骤:

  1. 分析优化解的结构
  2. 递归地定义最优解的代价
  3. 自底向上地计算优化解的代价保存之,并获取构造最优解的信息。
  4. 根据计算优化解的代价,构造优化解
 
可用动态规划方法求解的问题必须满足的条件
     1. 具有优化子结构(Optimal substructure)
     如果一个问题的优化解包含了他的子问题的优化解,则称此问题具有优化结构。如,A1A2A3A4A5A6 的优化解是 (A1 ( A2A3)) ((A4A5)A6),其中A1 ( A2A3)和(A4A5)A6),分别是A1A2A3和A4A5A6的解。
        优化结构是应用动态规划方法的一个条件。是必要条件!
     2. 具有重叠子问题(Overlapping sub-problems)  
       如果递归算法求解一个优化问题时,需要反复求解相同的子问题,则称该优化问题具有重叠子问题。
       动态规划算法利用该性质,以求得的子问题的解保存后,自底向上地,重复利用子问题的解获得上级问题的解,节省空间开销和时间开销。
       如果不具备重叠子问题的性质动态规划方法的空间开销和时间开销很大。利用动态规划算法没有意义!
 
求最长公共子序列
 
 1. 子序列定义
    设x=(x1, x2, ... xm)是一个序列, z=(z1, z2, ... zm) 是x的一个子序列,如果存在1i1<i2<...<ik<m, 使xij=zj
    z=(z1, z2, ... zm)即是x=(x1, x2, ... xm)中删除一些元素以后得到的序列。

2.公共子序列定义
    Z是序列X与Y的公共子序列,如果Z是X的子序列且Z是Y的子序列。
     
    3.最长公共子序列问题(LCS)
    输入:X=(x1, x2, ... xn),Y=(y1, y2, ...ym)
    输出:X与Y的最长公共子序列Z

 
最长公共子序列结构分析
        定义. 设X=(x1 , x2 , ... xn) 是一个序列, Xi表示X的第i个前缀,即 Xi=(x1 , ... xi )。
        例.  X=(A,B,D,C,A),  X1=(A),  X2=(A,B),  X3=(A,B,D)
 
优化解的结构
    定理1(LCS的优化结构)设X=(x1 , ... xm), Y=(y1 , y2 , ... yn)是两个序列,Z=(z1 , z2 , ... zk) 是X与Y的LCS。下列结论成立:
  1. 如xm= yn, 则zk=xm=yn, Zk-1是Xm-1和Yn-1的LCS,即,LCS(X,Y)=LCS(Xm-1,Yn-1)+xm
  2. 若xm != yn,且zk!=xm,则Z是Xm-1和Y的LCS,即   LCS(X,Y)=LCS(Xm-1,Y)
  3. 若xm != yn , 且zk !=yn,则Z是X与Yn-1的LCS,即    LCS(X,Y)=LCS(X,Yn-1)
 
例如:
 
 
 
建立求解LCS长度的递归方程
 
If xm= yn, xm属于X和Y的LCS,必须求解Xm-1和Yn-1的LCS。
If xm !=yn , 必须求解Xm-1和Y的LCS以及X和Yn-1 的LCS,长者是X和Y的LCS。C[i,j] 表示Xi与Yj的LCS的长度,则建立求解LCS长度的递归方程
 
LCS长度的计算
    1.基本思想
       计算C[i,j] 需先计算C[i-1,j-1]、C[i,j-1]、C[i-1,j]
 
C[i-1,j-1] C[ i, j-1]
C[i-1,   j] C[  i,   j]

先计算出第0行与第0列,然后逐行计算。

 

2.   算法

 
 
 
  1. /**
  2. *copyright@andy
  3. *date@ 2012/09/08
  4. * m : x的长度
  5. *  n : y的长度
  6. *  c : xi与yi的LCS的长度
  7. *  b : 用于标记xi和yi的关系
  8. **/
  9. void LCSLength( int m, int n, char *x, char *y int **c, Type **b )
  10. {
  11. int i, j;
  12. /*c 初始化*/
  13. for ( i=1; i<=m; i++) c[ 0 ][ i ]=0;
  14. for( j=1; j<=n, j++) c[ j ][0 ]=0;
  15. for ( i=1; i<=m; i++)
  16. for( j=1; j<=n, j++)
  17. {
  18. if(x[i]==y[j])  //xi = yj 时LCS 增1
  19. {
  20. c[ i ][ j ]=c[ i-1 ][ j-1]+1;
  21. b[ i ][ j ]='\'';
  22. }
  23. else if ( c[i-1][j] >= c[i][j-1]) //当xi ≠ yj时保存长子序列
  24. {
  25. c[ i ][ j ]=c[ i-1 ][ j];
  26. b[ i ][ j ]='|';
  27. }
  28. else
  29. {
  30. c[ i ][ j ]=c[ i ][ j-1];
  31. b[ i ][ j ]='--';
  32. }
  33. }
  34. }
 
3.   构造LCS算法
 
  1. /**
  2. *copyright@andy
  3. *date@ 2012/09/08
  4. * i : x的长度
  5. *  j : y的长度
  6. *  x : x字符串
  7. *  b : 用于标记xi和yi的关系
  8. **/
  9. void LCS( int i, int j, char *x, Type **b )
  10. {
  11. if ( i==0 || j==0) return;
  12. if (b[ i ][ j ] =='\'')//当xi = yj 时,输出xi ,并删除xi 和 yj ,之后在子序列中继续求解LCS
  13. {
  14. LCS(i-1, j-1, x, b);
  15. out<<x[ i ];
  16. }
  17. else if ( b[i][j] == '|')//当Xi-1 和 Yj 的LCS不小于Xi 和 Yj-1 的LCS 时
  18. LCS(i-1, j, x, b);    //在Xi-1 和 Yj中继续求解LCS;否则,在Xi 和 Yj-1 中继续求解LCS;
  19. else
  20. LCS( i, j-1, x, b);
  21. }

 
LCSLength算法的时间复杂性O(mn)

[algorithm]求最长公共子序列问题的更多相关文章

  1. HDU 4681 string 求最长公共子序列的简单DP+暴力枚举

    先预处理,用求最长公共子序列的DP顺着处理一遍,再逆着处理一遍. 再预处理串a和b中包含串c的子序列,当然,为了使这子序列尽可能短,会以c 串的第一个字符开始 ,c 串的最后一个字符结束 将这些起始位 ...

  2. HDU 1243 反恐训练营 (动态规划求最长公共子序列)

    反恐训练营 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Subm ...

  3. Java实现 LeetCode 583 两个字符串的删除操作(求最长公共子序列问题)

    583. 两个字符串的删除操作 给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符. 示例: 输入: " ...

  4. poj1458 求最长公共子序列 经典DP

    Common Subsequence Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 45763   Accepted: 18 ...

  5. codevs 1862 最长公共子序列(求最长公共子序列长度并统计最长公共子序列的个数)

    题目描述 Description 字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x0,x1,…,xm-1”,序列Y ...

  6. 动态规划求最长公共子序列(Longest Common Subsequence, LCS)

    1. 问题描述 子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与 ...

  7. 【dp】求最长公共子序列

    [题目描述] 一个给定序列的子序列是在该序列中删去若干元素后得到的序列.确切地说,若给定序列X=<x1,x2,…,xm>X=<x1,x2,…,xm>,则另一序列Z=<z1 ...

  8. Coincidence (动态规划求最长公共子序列)(王道)

    题目描述: Find a longest common subsequence of two strings. 输入: First and second line of each input case ...

  9. hdu 1159求最长公共子序列

    题目描述:给出两个字符串,求两个字符串的公共子序列(不是公共子串,不要求连续,但要符合在原字符串中的顺序) in: abcfbc abfcab programming contest abcd mnp ...

随机推荐

  1. Part 11 Search filter in AngularJS

    As we type in the search textbox, all the columns in the table must be searched and only the matchin ...

  2. js 平滑定位

    <script type="text/javascript"> function intval(v){ v = parseInt(v); return isNaN(v) ...

  3. Swift字典

    字典初始化 基本语法: [key 1: value 1, key 2: value 2, key 3: value 3] var   airports:    Dictionary<String ...

  4. dropdownlist值改变时调用js

    DropDownList的OnSelectedIndexChanged方法是服务器端方法如要用需要设置AutoPostBack选项为true,并且在服务器后台写方法 要调用js方法需要onchange ...

  5. 深刻理解C#中资源释放

    今天我的一个朋友看到我写的那篇<C#中用AJAX验证用户登录>时,给我指出了点小毛病.就是在用户登录时,如果用户登录失败,在下面这段代码中,都会new出来一个User对象,如果连续登录失败 ...

  6. 20150528—html使用Jquery遍历text文本框的非空验证

    <script src="jquery-1.7.2.min.js" type="text/javascript"></script> & ...

  7. 转载:简单介绍Python中的try和finally和with方法

    用 Python 做一件很平常的事情: 打开文件, 逐行读入, 最后关掉文件; 进一步的需求是, 这也许是程序中一个可选的功能, 如果有任何问题, 比如文件无法打开, 或是读取出错, 那么在函数内需要 ...

  8. DOS删除服务

    启动服务:   net   start   服务名   停止服务:   net   stop     服务名   卸载服务:   服务名   -uninstall 安装服务:sc create ser ...

  9. AR模式

    AR模式 在ThinkPHP框架中,一共存在两种操作模式:ORM模式与AR模式 ORM模式:① 实例化模型 ② 创建数据对象组装数组 ③ 调用相关方法执行相关操作 AR模式:① 实例化模型 ② 把数据 ...

  10. 安装Java EE失败,解决方案

    笔者安装Java EE(版本是java_ee_sdk-7-jdk7-windows-x64-ml.exe)时,遇到错误提示提示"Could not find the required ver ...