LIS学习总结
来源:互联网 发布:易语言取中间文本源码 编辑:程序博客网 时间:2024/06/04 20:15
1.LIS含义:最长递增子序列,可以连续,也可以不连续,只要是最长的就行,注意和连续递增子序列的区别。
2.算法功能:不仅可以求出给定序列的最长递增子序列的长度,而且可以求出给定以序列中任意项结尾的最长递增子序列的长度。
设数列a1,a2,a3,a4,a5........a(n-1),an, (也可以是字符串); a.解法:用动态规划求解主要是动态方程的推导: 1.设dp[i] : 以a[i]结尾的最长递增子序列的长度; 2.假设a[i]是a[j]的后继,即a[i]>a[j] (j<i) ,那么dp[i]=dp[j]+1,如果对于所有j:1-(i-1) a[i]<=a[j] 恒成立,那么dp[i]=1; 3.由2可知:dp[i]=1 if(a[i]>a[j]) dp[i]=max{ dp[j]+1,dp[i] } (1<=j<i ) 。代码如下:
for(i=1;i<=N;++i){ dp[i]=1; for(j=1;j<i;++j) { if(a[i]>a[j]) dp[i]=max(dp[i],dp[j]+1); }}
我们发现上述实现方法时间复杂度太高 对于较大数据不能采用这种方法
优化方案:用二分的思想来优化(必须有序)
步骤:1.设g[i]: 数列的递增子序列长度为 i 时的最小结尾;
2.将a1放入g[1] 代表递增子序列长度为1时的最小结尾是g[1];
3.将a[i] 插入到已经确定最小结尾的序列中 a[i] 的位置下标就代表以a[i]结尾的LIS的长度;
4.直到将a(2-n)都插入到g数组中算法结束,g数组的最大下标就表示a(1-n)的LIS长度。
g数组版:
g[1]=a[1];cnt=2;for(i=2;i<=N;++i){ int iter=lower_bound(g+1,g+cnt,a[i])-g;//左闭右开 严格单增的(用二分还是和函数一起扯) g[iter]=a[i]; if(iter==cnt) ++cnt; }
vector版:
vector<int> VEC; vector<int>::iterator iter;VEC.push_back(a[1]); //初始化将a[1]放进去 for(i=2;i<=N;++i)//循环插入剩余元素 { iter=lower_bound(VEC.begin(),VEC.end(),a[i])//查找a[i]应插入的位置 if(iter==VEC.end()) VEC.push_back(a[i]);//如果在区间外直接放入 else *iter=a[i]; //如在区间内 替换 }
注意:1.在插入的过程之中我们发现g数组是有序的所以采用了二分的方法;
2. lower_boune(begin,end,key) : 返回[begin,end) 地址区间内第一个>=key的地址,用于严格单增;
upper_bound(begin , end , key) : 返回第一个>key的地址, 用于非严格单增;
3.从以上过程中可以看到,我们不仅可以求出LIS的长度,而且可以求出 以任意元素结尾的LIS的长度 (如果需要用STL的容器保存较方便);
4. 结论:给定串的 非严格 ,连续,单调减的子串个数等于该串的 最长,严格单调增的子串的长度(即LIS长度); 证明:数列 a1,a2,a3,a4,a5,a6,a7; 假设此串的LIS(唯一性)是a3,a5,那么其他剩下的元素必然非严格,a1>=a2>a3 < a4 >=a5>=a6>=a7(可推广到一般情况);
5.根据4可以推断: 结论:给定串 非严格,单调增的子串个数等于该串的 最长,严格单减的最长字串的长度(LDS长度);
6.如果题目中含有二维的要求,那么将二维的转化成一维的,然后就可以用LIS的方法了(其实LIS就是题目的尽头,将题目中的条件适当转化就变成特别简单的问题了)。
打印LIS:从头开始逐个插入元素,每次插入只能插入到后面或者替换前一位插入的元素,这样就可以打印LIS了!!
#include<cstdio>#include<vector>#include<algorithm>using namespace std;vector<int> VEC; vector<int>::iterator iter;int a[100];void LIS(int N){ int i=0; VEC.clear(); VEC.push_back(a[1]); for(i=2;i<=N;++i) { iter=lower_bound(VEC.begin(),VEC.end(),a[i]); if(iter==VEC.end()) VEC.push_back(a[i]); else if(iter+1==VEC.end()) *iter=a[i];//只更新last就避免i之后的元素插入到i之前 }}int main(){ int T,N,i; scanf("%d",&T); while(T--) { scanf("%d",&N); for(i=1;i<=N;++i) scanf("%d",&a[i]); LIS(N); printf("%d\n",VEC.size()); for(iter=VEC.begin();iter!=VEC.end();++iter) { printf("%d ",*iter); } printf("\n"); } return 0; }
详细讲解: http://www.cnblogs.com/handsomecui/p/4692350.html
- LIS学习总结
- LIS学习小结
- LCS LIS LCIS学习、
- LCS/LIS/LCIS 模板总结
- LIS
- LIS
- LIS
- LIS
- LIS
- LIS
- LIS
- LIS
- LIS
- LIS
- LIS
- LIS
- LIS
- LIS++
- iOS设置行高的多种方式以及优先级区分
- C++笔试总结
- php中多种方法删除字符串中间的空格
- 软件调试学习(1)——分段地址,线性地址,物理地址
- 一个输出内容不同引发的问题
- LIS学习总结
- C++泛型编程1——函数模板实例化,模板参数,重载及特化
- 矩阵模板hdu5015,UVA 10655,UVA 11149
- 51Nod-1414-冰雕
- php中序列化与反序列化
- FFT(快速傅里叶变换)算法学习笔记
- Maven工程管理要点
- Ionic简介和环境安装
- php --post中提交数组参数