Dynamic Programming 学习笔记(二) LIS vs LCS
2012-01-05 18:03
218 查看
LIS (Longest Increasing Subsequence) 最长上升子序列。
题目:给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s1<s2<s3<…<sn并且这个子序列的长度最长。输出这个最长的长度。
LCS (Longest Common Subsequence) 最长公共子序列。
题目:一个数列 S,如果其分别是两个或多个已知数列的子序列,且是最长的序列,则S 称为已知序列的最长公共子序列。
LIS与LCS都是典型的DP问题。
对于LIS,有两种基本的算法。
1. 依次遍历整个序列,每一次求出从第一个数到当前这个数的最长上升子序列,直至遍历到最后一个数字为止,然后再取dp数组里最大的那个即为整个序列的最长上升子序列。我们用dp[i]来存放序列1-i的最长上升子序列的长度,那么dp[i]=max(dp[j])+1,(j∈[1, i-1]); 显然dp[1]=1,我们从i=2开始遍历后面的元素即可。O(N^2)复杂度。
2. 用f[k]表示长度为k的上升子序列最后一个数最小是多少。易知数组f是递增的。读到一个新的数x后,找到某个i使得x>f[i]且x<=f[i+1],于是用x去更新f[i+1];特别地,如果所有的f[i]都小于x,则增加f的长度。f的长度即为所求。由于f是递增的,因此可以采用二分查找,时间复杂度为O(nlgn)。
而对于LCS。
子问题的递归结构为
分析:设序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一个最长公共子序列Z=<z1, z2, …, 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的最长公共子序列。
其中Xm-1=<x1, x2, …, xm-1>,Yn-1=<y1, y2, …, yn-1>,Zk-1=<z1, z2, …, zk-1>。
用c[i,j]记录序列Xi和Yj的最长公共子序列的长度。其中Xi=<x1, x2, …, xi>,Yj=<y1, y2, …, yj>。当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故c[i,j]=0。
下图能够说明这个问题。
注意:最长公共子串(Longest CommonSubstring)和最长公共子序列(LongestCommon Subsequence, LCS)的区别:子串(Substring)是串的一个连续的部分,子序列(Subsequence)则是从不改变序列的顺序,而从序列中去掉任意的元素而获得的新序列
参考文献:
http://www.wutianqi.com/?p=1850
http://www.matrix67.com/blog/archives/112
/article/1361446.html
题目:给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s1<s2<s3<…<sn并且这个子序列的长度最长。输出这个最长的长度。
LCS (Longest Common Subsequence) 最长公共子序列。
题目:一个数列 S,如果其分别是两个或多个已知数列的子序列,且是最长的序列,则S 称为已知序列的最长公共子序列。
LIS与LCS都是典型的DP问题。
对于LIS,有两种基本的算法。
1. 依次遍历整个序列,每一次求出从第一个数到当前这个数的最长上升子序列,直至遍历到最后一个数字为止,然后再取dp数组里最大的那个即为整个序列的最长上升子序列。我们用dp[i]来存放序列1-i的最长上升子序列的长度,那么dp[i]=max(dp[j])+1,(j∈[1, i-1]); 显然dp[1]=1,我们从i=2开始遍历后面的元素即可。O(N^2)复杂度。
int LIS(int arr[1000], int n) { for(int i=1; i<=n; ++i) dp[i] = 0; int max; dp[1] = 1; for(int i = 2; i <= n; ++i) { for(int j=1; j < i; ++j) { if(arr[i] > arr[j] && dp[j] + 1 > dp[i]) dp[i] = dp[j] + 1; } if (dp[i] > max) max = dp[i]; } return max; }
2. 用f[k]表示长度为k的上升子序列最后一个数最小是多少。易知数组f是递增的。读到一个新的数x后,找到某个i使得x>f[i]且x<=f[i+1],于是用x去更新f[i+1];特别地,如果所有的f[i]都小于x,则增加f的长度。f的长度即为所求。由于f是递增的,因此可以采用二分查找,时间复杂度为O(nlgn)。
int bSearch(int num, int k) { int low=1, high=k; while(low<=high) { int mid=(low+high)/2; if(num>=b[mid]) low=mid+1; else high=mid-1; } return low; } int LIS_bak() { int low = 1, high = n; int k = 1; b[1] = p[1]; for(int i=2; i<=n; ++i) { if(p[i]>=b[k]) b[++k] = p[i]; else { int pos = bSearch(p[i], k); b[pos] = p[i]; } } return k; }
而对于LCS。
子问题的递归结构为
分析:设序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一个最长公共子序列Z=<z1, z2, …, 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的最长公共子序列。
其中Xm-1=<x1, x2, …, xm-1>,Yn-1=<y1, y2, …, yn-1>,Zk-1=<z1, z2, …, zk-1>。
用c[i,j]记录序列Xi和Yj的最长公共子序列的长度。其中Xi=<x1, x2, …, xi>,Yj=<y1, y2, …, yj>。当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故c[i,j]=0。
下图能够说明这个问题。
注意:最长公共子串(Longest CommonSubstring)和最长公共子序列(LongestCommon Subsequence, LCS)的区别:子串(Substring)是串的一个连续的部分,子序列(Subsequence)则是从不改变序列的顺序,而从序列中去掉任意的元素而获得的新序列
参考文献:
http://www.wutianqi.com/?p=1850
http://www.matrix67.com/blog/archives/112
/article/1361446.html
相关文章推荐
- LIS,LCS,LICS 学习笔记
- VS2013MFC单文档工程学习笔记四 - 动态创建多个控件
- vscode 学习笔记 —— 重构
- 学习笔记:openssl , AES, vs2015
- VS插件开发学习笔记:VS2008所有菜单名字
- cocos2d-x-3.1 vs 输出Log的几种方法 (coco2d-x 学习笔记三)
- VS 2008 Feature Pack界面开发学习笔记之初步接触
- ASP: VS2015 + IIS Express 10 学习笔记
- opengl学习笔记1:vs2013 nehe教程第一课 创建窗口
- Qt-学习笔记(1):vs2015使用qt静态库5.5.1
- object-c学习笔记:new vs alloc init
- 菜鸟学习笔记-msi,vs2013配置openssl
- [libjingle学习笔记]libjingle生成vs工程文件
- VS 学习笔记-WINDOWS程序机制及窗口创建
- [转]NUnit学习笔记 VS.net 2005篇
- VS2013MFC对话框工程学习笔记四 - 为按钮添加一个响应事件二
- NUnit学习笔记 VS.net 2005篇
- Nutch学习笔记9---fetch优化 protocol-http VS httpclient
- OpenGL学习笔记--配置VS环境
- Udacity cs344-Introduction to Parallel Programming学习笔记-如何在VS环境下编译课程习题代码